diff --git a/.gitignore b/.gitignore index c438a51629c0..21905c804f7d 100644 --- a/.gitignore +++ b/.gitignore @@ -30,9 +30,7 @@ ################ # setup.py working directory build -# sphinx build directory -doc/_build -doc/gallery + # setup.py dist directory dist # Egg metadata @@ -58,9 +56,13 @@ lib/matplotlib/mpl-data/matplotlibrc # Documentation generated files # ################################# +# sphinx build directory +doc/_build doc/api/_as_gen -doc/examples # autogenerated by sphinx-gallery +doc/examples +doc/gallery +doc/tutorials doc/modules doc/pyplots/tex_demo.png doc/users/installing.rst diff --git a/doc/faq/anatomy.png b/doc/_static/anatomy.png similarity index 100% rename from doc/faq/anatomy.png rename to doc/_static/anatomy.png diff --git a/doc/_static/mpl.css b/doc/_static/mpl.css index d94b594cbb07..d7bc46446c7f 100644 --- a/doc/_static/mpl.css +++ b/doc/_static/mpl.css @@ -785,9 +785,9 @@ div.responsive_subfig img { div.responsive_subfig { width: 50%; /* we want 2 subfigs in a row */ } +} /* Sphinx gallery display */ -} div.align-center { margin: auto; @@ -798,6 +798,31 @@ p.caption { font-weight: bold; } -div#gallery.section { +div#gallery.section, div#tutorials.section { overflow: hidden; } + +.sphx-glr-thumbcontainer { + border: solid #d6d6d6 1px !important; + text-align: center !important; + font-size: 1.2em !important; +} + +div.sphx-glr-download { + width: auto !important; +} + +div.sphx-glr-download a { + background-color: #d9edf7 !important; + border: 1px solid #bce8f1 !important; + background-image: none !important; +} + +p.sphx-glr-signature a.reference.external { + display: none !important; +} + +.sphx-glr-thumbcontainer a.internal { + font-weight: 400; +} + diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html index b5bd37d2c3b5..9ee83391adc4 100644 --- a/doc/_templates/layout.html +++ b/doc/_templates/layout.html @@ -39,6 +39,7 @@

{{ _('Navigation') }}

  • home
  • examples
  • +
  • tutorials
  • pyplot
  • docs »
  • diff --git a/doc/api/animation_api.rst b/doc/api/animation_api.rst index 46323e15db88..b36d4cc85f55 100644 --- a/doc/api/animation_api.rst +++ b/doc/api/animation_api.rst @@ -243,7 +243,7 @@ to use the `~MovieWriter.saving` context manager :: to ensures that setup and cleanup are performed as necessary. -:ref:`animation-moviewriter` +:ref:`sphx_glr_gallery_animation_moviewriter_sgskip.py` .. _ani_writer_classes: @@ -267,7 +267,7 @@ Animation Base Classes Custom Animation classes ------------------------ -:ref:`animation-subplots` +:ref:`sphx_glr_gallery_animation_subplots.py` Writer Registry --------------- diff --git a/doc/api/api_changes.rst b/doc/api/api_changes.rst index d4fbf5bd2689..a0e16ebb0edf 100644 --- a/doc/api/api_changes.rst +++ b/doc/api/api_changes.rst @@ -782,7 +782,7 @@ original location: * The legend handler interface has changed from a callable, to any object which implements the ``legend_artists`` method (a deprecation phase will see this interface be maintained for v1.4). See - :ref:`plotting-guide-legend` for further details. Further legend changes + :ref:`sphx_glr_tutorials_02_intermediate_legend_guide.py` for further details. Further legend changes include: * :func:`matplotlib.axes.Axes._get_legend_handles` now returns a generator diff --git a/doc/conf.py b/doc/conf.py index 3ecdff7de1e0..301df0055687 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -105,9 +105,9 @@ # Sphinx gallery configuration sphinx_gallery_conf = { - 'examples_dirs': '../examples', + 'examples_dirs': ['../examples', '../tutorials'], 'filename_pattern': '^((?!sgskip).)*$', - 'gallery_dirs': 'gallery', + 'gallery_dirs': ['gallery', 'tutorials'], 'doc_module': ('matplotlib',), 'reference_url': {'matplotlib': None, 'numpy': 'http://docs.scipy.org/doc/numpy/reference', diff --git a/doc/devel/contributing.rst b/doc/devel/contributing.rst index 616c235a3e6d..4e2178bddc05 100644 --- a/doc/devel/contributing.rst +++ b/doc/devel/contributing.rst @@ -414,7 +414,7 @@ Developing a new backend ------------------------ If you are working on a custom backend, the *backend* setting in -:file:`matplotlibrc` (:ref:`customizing-matplotlib`) supports an +:file:`matplotlibrc` (:ref:`sphx_glr_tutorials_01_introductory_customizing.py`) supports an external backend via the ``module`` directive. If :file:`my_backend.py` is a Matplotlib backend in your :envvar:`PYTHONPATH`, you can set it on one of several ways diff --git a/doc/faq/howto_faq.rst b/doc/faq/howto_faq.rst index 4849bc543448..7ac820021c4f 100644 --- a/doc/faq/howto_faq.rst +++ b/doc/faq/howto_faq.rst @@ -48,7 +48,7 @@ If you only want to use the `pandas` converter for `datetime64` values :: Find all objects in a figure of a certain type ---------------------------------------------- -Every Matplotlib artist (see :ref:`artist-tutorial`) has a method +Every Matplotlib artist (see :ref:`sphx_glr_tutorials_02_intermediate_artists.py`) has a method called :meth:`~matplotlib.artist.Artist.findobj` that can be used to recursively search the artist for any artists it may contain that meet some criteria (e.g., match all :class:`~matplotlib.lines.Line2D` @@ -160,7 +160,7 @@ labels:: ax = fig.add_subplot(111) You can control the defaults for these parameters in your -:file:`matplotlibrc` file; see :ref:`customizing-matplotlib`. For +:file:`matplotlibrc` file; see :ref:`sphx_glr_tutorials_01_introductory_customizing.py`. For example, to make the above setting permanent, you would set:: figure.subplot.bottom : 0.2 # the bottom of the subplots of the figure @@ -191,7 +191,7 @@ specify the location explicitly:: ax = fig.add_axes([left, bottom, width, height]) where all values are in fractional (0 to 1) coordinates. See -:ref:`pylab_examples-axes_demo` for an example of placing axes manually. +:ref:`sphx_glr_gallery_pylab_examples_axes_demo.py` for an example of placing axes manually. .. _howto-auto-adjust: @@ -201,7 +201,7 @@ Automatically make room for tick labels .. note:: This is now easier to handle than ever before. Calling :func:`~matplotlib.pyplot.tight_layout` can fix many common - layout issues. See the :ref:`plotting-guide-tight-layout`. + layout issues. See the :ref:`sphx_glr_tutorials_02_intermediate_tight_layout_guide.py`. The information below is kept here in case it is useful for other purposes. @@ -340,7 +340,7 @@ and patches, respectively:: .. htmlonly:: - See :ref:`pylab_examples-zorder_demo` for a complete example. + See :ref:`sphx_glr_gallery_pylab_examples_zorder_demo.py` for a complete example. You can also use the Axes property :meth:`~matplotlib.axes.Axes.set_axisbelow` to control whether the grid @@ -361,7 +361,7 @@ some ratio which controls the ratio:: .. htmlonly:: - See :ref:`subplots_axes_and_figures-equal_aspect_ratio` for a complete + See :ref:`sphx_glr_gallery_subplots_axes_and_figures_equal_aspect_ratio.py` for a complete example. @@ -406,7 +406,7 @@ locators as desired because the two axes are independent. .. htmlonly:: - See :ref:`api-two_scales` for a complete example + See :ref:`sphx_glr_gallery_api_two_scales.py` for a complete example .. _howto-batch: @@ -652,7 +652,7 @@ For more on configuring your backend, see Alternatively, you can avoid pylab/pyplot altogether, which will give you a little more control, by calling the API directly as shown in -:ref:`api-agg_oo`. +:ref:`sphx_glr_gallery_api_agg_oo_sgskip.py`. You can either generate hardcopy on the filesystem by calling savefig:: diff --git a/doc/faq/index.rst b/doc/faq/index.rst index 492491efca52..12feae4ed01c 100644 --- a/doc/faq/index.rst +++ b/doc/faq/index.rst @@ -15,7 +15,6 @@ The Matplotlib FAQ :maxdepth: 2 installing_faq.rst - usage_faq.rst howto_faq.rst troubleshooting_faq.rst environment_variables_faq.rst diff --git a/doc/faq/installing_faq.rst b/doc/faq/installing_faq.rst index c041d980b5e1..8d98db30fff6 100644 --- a/doc/faq/installing_faq.rst +++ b/doc/faq/installing_faq.rst @@ -34,7 +34,7 @@ and run it with:: This will give you additional information about which backends matplotlib is loading, version information, and more. At this point you might want to make -sure you understand matplotlib's :ref:`configuration ` +sure you understand matplotlib's :ref:`configuration ` process, governed by the :file:`matplotlibrc` configuration file which contains instructions within and the concept of the matplotlib backend. diff --git a/doc/faq/troubleshooting_faq.rst b/doc/faq/troubleshooting_faq.rst index 02e5d82bc736..a24d4135ea6d 100644 --- a/doc/faq/troubleshooting_faq.rst +++ b/doc/faq/troubleshooting_faq.rst @@ -108,7 +108,7 @@ please provide the following information in your e-mail to the * any customizations to your ``matplotlibrc`` file (see - :ref:`customizing-matplotlib`). + :ref:`sphx_glr_tutorials_01_introductory_customizing.py`). * if the problem is reproducible, please try to provide a *minimal*, standalone Python script that demonstrates the problem. This is diff --git a/doc/faq/usage_faq.rst b/doc/faq/usage_faq.rst deleted file mode 100644 index 413e0aaa0818..000000000000 --- a/doc/faq/usage_faq.rst +++ /dev/null @@ -1,619 +0,0 @@ -.. _usage-faq: - -*************** -Usage -*************** - -.. contents:: - :backlinks: none - - -.. _general_concepts: - -General Concepts -================ - -:mod:`matplotlib` has an extensive codebase that can be daunting to many -new users. However, most of matplotlib can be understood with a fairly -simple conceptual framework and knowledge of a few important points. - -Plotting requires action on a range of levels, from the most general -(e.g., 'contour this 2-D array') to the most specific (e.g., 'color -this screen pixel red'). The purpose of a plotting package is to assist -you in visualizing your data as easily as possible, with all the necessary -control -- that is, by using relatively high-level commands most of -the time, and still have the ability to use the low-level commands when -needed. - -Therefore, everything in matplotlib is organized in a hierarchy. At the top -of the hierarchy is the matplotlib "state-machine environment" which is -provided by the :mod:`matplotlib.pyplot` module. At this level, simple -functions are used to add plot elements (lines, images, text, etc.) to -the current axes in the current figure. - -.. note:: - Pyplot's state-machine environment behaves similarly to MATLAB and - should be most familiar to users with MATLAB experience. - -The next level down in the hierarchy is the first level of the object-oriented -interface, in which pyplot is used only for a few functions such as figure -creation, and the user explicitly creates and keeps track of the figure -and axes objects. At this level, the user uses pyplot to create figures, -and through those figures, one or more axes objects can be created. These -axes objects are then used for most plotting actions. - -For even more control -- which is essential for things like embedding -matplotlib plots in GUI applications -- the pyplot level may be dropped -completely, leaving a purely object-oriented approach. - -.. _figure_parts: - -Parts of a Figure -================= -.. image:: anatomy.png - -:class:`~matplotlib.figure.Figure` ----------------------------------- - -The **whole** figure. The figure keeps -track of all the child :class:`~matplotlib.axes.Axes`, a smattering of -'special' artists (titles, figure legends, etc), and the **canvas**. -(Don't worry too much about the canvas, it is crucial as it is the -object that actually does the drawing to get you your plot, but as the -user it is more-or-less invisible to you). A figure can have any -number of :class:`~matplotlib.axes.Axes`, but to be useful should have -at least one. - -The easiest way to create a new figure is with pyplot:: - - fig = plt.figure() # an empty figure with no axes - fig, ax_lst = plt.subplots(2, 2) # a figure with a 2x2 grid of Axes - - -:class:`~matplotlib.axes.Axes` ------------------------------- - -This is what you think of as 'a plot', it is the region of the image -with the data space (marked as the inner blue box). A given figure -can contain many Axes, but a given :class:`~matplotlib.axes.Axes` -object can only be in one :class:`~matplotlib.figure.Figure`. The -Axes contains two (or three in the case of 3D) -:class:`~matplotlib.axis.Axis` objects (be aware of the difference -between **Axes** and **Axis**) which take care of the data limits (the -data limits can also be controlled via set via the -:meth:`~matplotlib.axes.Axes.set_xlim` and -:meth:`~matplotlib.axes.Axes.set_ylim` :class:`Axes` methods). Each -:class:`Axes` has a title (set via -:meth:`~matplotlib.axes.Axes.set_title`), an x-label (set via -:meth:`~matplotlib.axes.Axes.set_xlabel`), and a y-label set via -:meth:`~matplotlib.axes.Axes.set_ylabel`). - -The :class:`Axes` class and it's member functions are the primary entry -point to working with the OO interface. - -:class:`~matplotlib.axis.Axis` ------------------------------- - -These are the number-line-like objects (circled in green). They take -care of setting the graph limits and generating the ticks (the marks -on the axis) and ticklabels (strings labeling the ticks). The -location of the ticks is determined by a -:class:`~matplotlib.ticker.Locator` object and the ticklabel strings -are formatted by a :class:`~matplotlib.ticker.Formatter`. The -combination of the correct :class:`Locator` and :class:`Formatter` gives -very fine control over the tick locations and labels. - -:class:`~matplotlib.artist.Artist` ----------------------------------- - -Basically everything you can see on the figure is an artist (even the -:class:`Figure`, :class:`Axes`, and :class:`Axis` objects). This -includes :class:`Text` objects, :class:`Line2D` objects, -:class:`collection` objects, :class:`Patch` objects ... (you get the -idea). When the figure is rendered, all of the artists are drawn to -the **canvas**. Most Artists are tied to an Axes; such an Artist -cannot be shared by multiple Axes, or moved from one to another. - -.. _input_types: - -Types of inputs to plotting functions -===================================== - -All of plotting functions expect `np.array` or `np.ma.masked_array` as -input. Classes that are 'array-like' such as `pandas` data objects -and `np.matrix` may or may not work as intended. It is best to -convert these to `np.array` objects prior to plotting. - -For example, to covert a `pandas.DataFrame` :: - - a = pandas.DataFrame(np.random.rand(4,5), columns = list('abcde')) - a_asndarray = a.values - -and to covert a `np.matrix` :: - - b = np.matrix([[1,2],[3,4]]) - b_asarray = np.asarray(b) - - - -.. _pylab: - -Matplotlib, pyplot and pylab: how are they related? -==================================================== - -Matplotlib is the whole package; :mod:`matplotlib.pyplot` -is a module in matplotlib; and :mod:`pylab` is a module -that gets installed alongside :mod:`matplotlib`. - -Pyplot provides the state-machine interface to the underlying -object-oriented plotting library. The state-machine implicitly and -automatically creates figures and axes to achieve the desired -plot. For example:: - - - import matplotlib.pyplot as plt - import numpy as np - - x = np.linspace(0, 2, 100) - - plt.plot(x, x, label='linear') - plt.plot(x, x**2, label='quadratic') - plt.plot(x, x**3, label='cubic') - - plt.xlabel('x label') - plt.ylabel('y label') - - plt.title("Simple Plot") - - plt.legend() - - plt.show() - -The first call to ``plt.plot`` will automatically create the necessary -figure and axes to achieve the desired plot. Subsequent calls to -``plt.plot`` re-use the current axes and each add another line. -Setting the title, legend, and axis labels also automatically use the -current axes and set the title, create the legend, and label the axis -respectively. - -:mod:`pylab` is a convenience module that bulk imports -:mod:`matplotlib.pyplot` (for plotting) and :mod:`numpy` -(for mathematics and working with arrays) in a single name space. -Although many examples use :mod:`pylab`, it is no longer recommended. - -For non-interactive plotting it is suggested -to use pyplot to create the figures and then the OO interface for -plotting. - -.. _coding_styles: - -Coding Styles -================== - -When viewing this documentation and examples, you will find different -coding styles and usage patterns. These styles are perfectly valid -and have their pros and cons. Just about all of the examples can be -converted into another style and achieve the same results. -The only caveat is to avoid mixing the coding styles for your own code. - -.. note:: - Developers for matplotlib have to follow a specific style and guidelines. - See :ref:`developers-guide-index`. - -Of the different styles, there are two that are officially supported. -Therefore, these are the preferred ways to use matplotlib. - -For the pyplot style, the imports at the top of your -scripts will typically be:: - - import matplotlib.pyplot as plt - import numpy as np - -Then one calls, for example, np.arange, np.zeros, np.pi, plt.figure, -plt.plot, plt.show, etc. Use the pyplot interface -for creating figures, and then use the object methods for the rest:: - - import matplotlib.pyplot as plt - import numpy as np - x = np.arange(0, 10, 0.2) - y = np.sin(x) - fig = plt.figure() - ax = fig.add_subplot(111) - ax.plot(x, y) - plt.show() - -So, why all the extra typing instead of the MATLAB-style (which relies -on global state and a flat namespace)? For very simple things like -this example, the only advantage is academic: the wordier styles are -more explicit, more clear as to where things come from and what is -going on. For more complicated applications, this explicitness and -clarity becomes increasingly valuable, and the richer and more -complete object-oriented interface will likely make the program easier -to write and maintain. - - -Typically one finds oneself making the same plots over and over -again, but with different data sets, which leads to needing to write -specialized functions to do the plotting. The recommended function -signature is something like: :: - - def my_plotter(ax, data1, data2, param_dict): - """ - A helper function to make a graph - - Parameters - ---------- - ax : Axes - The axes to draw to - - data1 : array - The x data - - data2 : array - The y data - - param_dict : dict - Dictionary of kwargs to pass to ax.plot - - Returns - ------- - out : list - list of artists added - """ - out = ax.plot(data1, data2, **param_dict) - return out - -which you would then use as:: - - fig, ax = plt.subplots(1, 1) - my_plotter(ax, data1, data2, {'marker':'x'}) - - -or if you wanted to have 2 sub-plots:: - - fig, (ax1, ax2) = plt.subplots(1, 2) - my_plotter(ax1, data1, data2, {'marker':'x'}) - my_plotter(ax2, data3, data4, {'marker':'o'}) - -Again, for these simple examples this style seems like overkill, however -once the graphs get slightly more complex it pays off. - -.. _what-is-a-backend: - -What is a backend? -================== - -A lot of documentation on the website and in the mailing lists refers -to the "backend" and many new users are confused by this term. -matplotlib targets many different use cases and output formats. Some -people use matplotlib interactively from the python shell and have -plotting windows pop up when they type commands. Some people embed -matplotlib into graphical user interfaces like wxpython or pygtk to -build rich applications. Others use matplotlib in batch scripts to -generate postscript images from some numerical simulations, and still -others in web application servers to dynamically serve up graphs. - -To support all of these use cases, matplotlib can target different -outputs, and each of these capabilities is called a backend; the -"frontend" is the user facing code, i.e., the plotting code, whereas the -"backend" does all the hard work behind-the-scenes to make the figure. -There are two types of backends: user interface backends (for use in -pygtk, wxpython, tkinter, qt4, or macosx; also referred to as -"interactive backends") and hardcopy backends to make image files -(PNG, SVG, PDF, PS; also referred to as "non-interactive backends"). - -There are four ways to configure your backend. If they conflict each other, -the method mentioned last in the following list will be used, e.g. calling -:func:`~matplotlib.use()` will override the setting in your ``matplotlibrc``. - - -#. The ``backend`` parameter in your ``matplotlibrc`` file (see - :ref:`customizing-matplotlib`):: - - backend : WXAgg # use wxpython with antigrain (agg) rendering - -#. Setting the :envvar:`MPLBACKEND` environment - variable, either for your current shell or for a single script:: - - > export MPLBACKEND="module://my_backend" - > python simple_plot.py - - > MPLBACKEND="module://my_backend" python simple_plot.py - - Setting this environment variable will override the ``backend`` parameter - in *any* ``matplotlibrc``, even if there is a ``matplotlibrc`` in your - current working directory. Therefore setting :envvar:`MPLBACKEND` - globally, e.g. in your ``.bashrc`` or ``.profile``, is discouraged as it - might lead to counter-intuitive behavior. - -#. If your script depends on a specific backend you can use the - :func:`~matplotlib.use` function:: - - import matplotlib - matplotlib.use('PS') # generate postscript output by default - - If you use the :func:`~matplotlib.use` function, this must be done before - importing :mod:`matplotlib.pyplot`. Calling :func:`~matplotlib.use` after - pyplot has been imported will have no effect. Using - :func:`~matplotlib.use` will require changes in your code if users want to - use a different backend. Therefore, you should avoid explicitly calling - :func:`~matplotlib.use` unless absolutely necessary. - -.. note:: - Backend name specifications are not case-sensitive; e.g., 'GTKAgg' - and 'gtkagg' are equivalent. - -With a typical installation of matplotlib, such as from a -binary installer or a linux distribution package, a good default -backend will already be set, allowing both interactive work and -plotting from scripts, with output to the screen and/or to -a file, so at least initially you will not need to use any of the -methods given above. - -If, however, you want to write graphical user interfaces, or a web -application server (:ref:`howto-webapp`), or need a better -understanding of what is going on, read on. To make things a little -more customizable for graphical user interfaces, matplotlib separates -the concept of the renderer (the thing that actually does the drawing) -from the canvas (the place where the drawing goes). The canonical -renderer for user interfaces is ``Agg`` which uses the `Anti-Grain -Geometry`_ C++ library to make a raster (pixel) image of the figure. -All of the user interfaces except ``macosx`` can be used with -agg rendering, e.g., -``WXAgg``, ``GTKAgg``, ``QT4Agg``, ``QT5Agg``, ``TkAgg``. In -addition, some of the user interfaces support other rendering engines. -For example, with GTK, you can also select GDK rendering (backend -``GTK`` deprecated in 2.0) or Cairo rendering (backend ``GTKCairo``). - -For the rendering engines, one can also distinguish between `vector -`_ or `raster -`_ renderers. Vector -graphics languages issue drawing commands like "draw a line from this -point to this point" and hence are scale free, and raster backends -generate a pixel representation of the line whose accuracy depends on a -DPI setting. - -Here is a summary of the matplotlib renderers (there is an eponymous -backed for each; these are *non-interactive backends*, capable of -writing to a file): - -============= ============ ================================================ -Renderer Filetypes Description -============= ============ ================================================ -:term:`AGG` :term:`png` :term:`raster graphics` -- high quality images - using the `Anti-Grain Geometry`_ engine -PS :term:`ps` :term:`vector graphics` -- Postscript_ output - :term:`eps` -PDF :term:`pdf` :term:`vector graphics` -- - `Portable Document Format`_ -SVG :term:`svg` :term:`vector graphics` -- - `Scalable Vector Graphics`_ -:term:`Cairo` :term:`png` :term:`vector graphics` -- - :term:`ps` `Cairo graphics`_ - :term:`pdf` - :term:`svg` - ... -:term:`GDK` :term:`png` :term:`raster graphics` -- - :term:`jpg` the `Gimp Drawing Kit`_ Deprecated in 2.0 - :term:`tiff` - ... -============= ============ ================================================ - -And here are the user interfaces and renderer combinations supported; -these are *interactive backends*, capable of displaying to the screen -and of using appropriate renderers from the table above to write to -a file: - -============ ================================================================ -Backend Description -============ ================================================================ -GTKAgg Agg rendering to a :term:`GTK` 2.x canvas (requires PyGTK_ and - pycairo_ or cairocffi_; Python2 only) -GTK3Agg Agg rendering to a :term:`GTK` 3.x canvas (requires PyGObject_ - and pycairo_ or cairocffi_) -GTK GDK rendering to a :term:`GTK` 2.x canvas (not recommended and d - eprecated in 2.0) (requires PyGTK_ and pycairo_ or cairocffi_; - Python2 only) -GTKCairo Cairo rendering to a :term:`GTK` 2.x canvas (requires PyGTK_ - and pycairo_ or cairocffi_; Python2 only) -GTK3Cairo Cairo rendering to a :term:`GTK` 3.x canvas (requires PyGObject_ - and pycairo_ or cairocffi_) -WXAgg Agg rendering to to a :term:`wxWidgets` canvas - (requires wxPython_) -WX Native :term:`wxWidgets` drawing to a :term:`wxWidgets` Canvas - (not recommended and deprecated in 2.0) (requires wxPython_) -TkAgg Agg rendering to a :term:`Tk` canvas (requires TkInter_) -Qt4Agg Agg rendering to a :term:`Qt4` canvas (requires PyQt4_ or ``pyside``) -Qt5Agg Agg rendering in a :term:`Qt5` canvas (requires PyQt5_) -macosx Cocoa rendering in OSX windows - (presently lacks blocking show() behavior when matplotlib - is in non-interactive mode) -============ ================================================================ - -.. _`Anti-Grain Geometry`: http://antigrain.com/ -.. _Postscript: https://en.wikipedia.org/wiki/PostScript -.. _`Portable Document Format`: https://en.wikipedia.org/wiki/Portable_Document_Format -.. _`Scalable Vector Graphics`: https://en.wikipedia.org/wiki/Scalable_Vector_Graphics -.. _`Cairo graphics`: https://en.wikipedia.org/wiki/Cairo_(graphics) -.. _`Gimp Drawing Kit`: https://en.wikipedia.org/wiki/GDK -.. _PyGTK: http://www.pygtk.org -.. _PyGObject: https://wiki.gnome.org/action/show/Projects/PyGObject -.. _pycairo: https://www.cairographics.org/pycairo/ -.. _cairocffi: https://pythonhosted.org/cairocffi/ -.. _wxPython: https://www.wxpython.org/ -.. _TkInter: https://wiki.python.org/moin/TkInter -.. _PyQt4: https://riverbankcomputing.com/software/pyqt/intro -.. _PyQt5: https://riverbankcomputing.com/software/pyqt/intro - -WX backends -=========== - -At present the release version of `wxPython` (also known as wxPython classic) -does not support python3. A work in progress redesigned version known as -wxPython-Phoenix_ does support python3. -Matplotlib should work with both versions. - -.. _wxPython-Phoenix: https://wxpython.org/Phoenix/docs/html/main.html - -GTK and Cairo -============= - -Both `GTK2` and `GTK3` have implicit dependencies on PyCairo regardless of the -specific Matplotlib backend used. Unfortunatly the latest release of PyCairo -for Python3 does not implement the Python wrappers needed for the `GTK3Agg` -backend. `Cairocffi` can be used as a replacement which implements the correct -wrapper. - -How do I select PyQt4 or PySide? -======================================== - -You can choose either PyQt4 or PySide when using the `qt4` backend by setting -the appropriate value for `backend.qt4` in your :file:`matplotlibrc` file. The -default value is `PyQt4`. - -The setting in your :file:`matplotlibrc` file can be overridden by setting the -`QT_API` environment variable to either `pyqt` or `pyside` to use `PyQt4` or -`PySide`, respectively. - -Since the default value for the bindings to be used is `PyQt4`, -:mod:`matplotlib` first tries to import it, if the import fails, it tries to -import `PySide`. - -.. _interactive-mode: - -What is interactive mode? -=================================== - -Use of an interactive backend (see :ref:`what-is-a-backend`) -permits--but does not by itself require or ensure--plotting -to the screen. Whether and when plotting to the screen occurs, -and whether a script or shell session continues after a plot -is drawn on the screen, depends on the functions and methods -that are called, and on a state variable that determines whether -matplotlib is in "interactive mode". The default Boolean value is set -by the :file:`matplotlibrc` file, and may be customized like any other -configuration parameter (see :ref:`customizing-matplotlib`). It -may also be set via :func:`matplotlib.interactive`, and its -value may be queried via :func:`matplotlib.is_interactive`. Turning -interactive mode on and off in the middle of a stream of plotting -commands, whether in a script or in a shell, is rarely needed -and potentially confusing, so in the following we will assume all -plotting is done with interactive mode either on or off. - -.. note:: - Major changes related to interactivity, and in particular the - role and behavior of :func:`~matplotlib.pyplot.show`, were made in the - transition to matplotlib version 1.0, and bugs were fixed in - 1.0.1. Here we describe the version 1.0.1 behavior for the - primary interactive backends, with the partial exception of - *macosx*. - -Interactive mode may also be turned on via :func:`matplotlib.pyplot.ion`, -and turned off via :func:`matplotlib.pyplot.ioff`. - -.. note:: - Interactive mode works with suitable backends in ipython and in - the ordinary python shell, but it does *not* work in the IDLE IDE. - If the default backend does not support interactivity, an interactive - backend can be explicitly activated using any of the methods discussed in `What is a backend?`_. - - -Interactive example --------------------- - -From an ordinary python prompt, or after invoking ipython with no options, -try this:: - - import matplotlib.pyplot as plt - plt.ion() - plt.plot([1.6, 2.7]) - -Assuming you are running version 1.0.1 or higher, and you have -an interactive backend installed and selected by default, you should -see a plot, and your terminal prompt should also be active; you -can type additional commands such as:: - - plt.title("interactive test") - plt.xlabel("index") - -and you will see the plot being updated after each line. This is -because you are in interactive mode *and* you are using pyplot -functions. Now try an alternative method of modifying the -plot. Get a reference to the :class:`~matplotlib.axes.Axes` instance, and -call a method of that instance:: - - ax = plt.gca() - ax.plot([3.1, 2.2]) - -Nothing changed, because the Axes methods do not include an -automatic call to :func:`~matplotlib.pyplot.draw_if_interactive`; -that call is added by the pyplot functions. If you are using -methods, then when you want to update the plot on the screen, -you need to call :func:`~matplotlib.pyplot.draw`:: - - plt.draw() - -Now you should see the new line added to the plot. - -Non-interactive example ------------------------ - -Start a fresh session as in the previous example, but now -turn interactive mode off:: - - import matplotlib.pyplot as plt - plt.ioff() - plt.plot([1.6, 2.7]) - -Nothing happened--or at least nothing has shown up on the -screen (unless you are using *macosx* backend, which is -anomalous). To make the plot appear, you need to do this:: - - plt.show() - -Now you see the plot, but your terminal command line is -unresponsive; the :func:`show()` command *blocks* the input -of additional commands until you manually kill the plot -window. - -What good is this--being forced to use a blocking function? -Suppose you need a script that plots the contents of a file -to the screen. You want to look at that plot, and then end -the script. Without some blocking command such as show(), the -script would flash up the plot and then end immediately, -leaving nothing on the screen. - -In addition, non-interactive mode delays all drawing until -show() is called; this is more efficient than redrawing -the plot each time a line in the script adds a new feature. - -Prior to version 1.0, show() generally could not be called -more than once in a single script (although sometimes one -could get away with it); for version 1.0.1 and above, this -restriction is lifted, so one can write a script like this:: - - import numpy as np - import matplotlib.pyplot as plt - plt.ioff() - for i in range(3): - plt.plot(np.random.rand(10)) - plt.show() - -which makes three plots, one at a time. - -Summary -------- - -In interactive mode, pyplot functions automatically draw -to the screen. - -When plotting interactively, if using -object method calls in addition to pyplot functions, then -call :func:`~matplotlib.pyplot.draw` whenever you want to -refresh the plot. - -Use non-interactive mode in scripts in which you want to -generate one or more figures and display them before ending -or generating a new set of figures. In that case, use -:func:`~matplotlib.pyplot.show` to display the figure(s) and -to block execution until you have manually destroyed them. diff --git a/doc/users/artists.rst b/doc/users/artists.rst deleted file mode 100644 index c051374781f8..000000000000 --- a/doc/users/artists.rst +++ /dev/null @@ -1,662 +0,0 @@ -.. _artist-tutorial: - -*************** -Artist tutorial -*************** - -There are three layers to the matplotlib API. The -:class:`matplotlib.backend_bases.FigureCanvas` is the area onto which -the figure is drawn, the :class:`matplotlib.backend_bases.Renderer` is -the object which knows how to draw on the -:class:`~matplotlib.backend_bases.FigureCanvas`, and the -:class:`matplotlib.artist.Artist` is the object that knows how to use -a renderer to paint onto the canvas. The -:class:`~matplotlib.backend_bases.FigureCanvas` and -:class:`~matplotlib.backend_bases.Renderer` handle all the details of -talking to user interface toolkits like `wxPython -`_ or drawing languages like PostScript®, and -the ``Artist`` handles all the high level constructs like representing -and laying out the figure, text, and lines. The typical user will -spend 95% of their time working with the ``Artists``. - -There are two types of ``Artists``: primitives and containers. The primitives -represent the standard graphical objects we want to paint onto our canvas: -:class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.patches.Rectangle`, -:class:`~matplotlib.text.Text`, :class:`~matplotlib.image.AxesImage`, etc., and -the containers are places to put them (:class:`~matplotlib.axis.Axis`, -:class:`~matplotlib.axes.Axes` and :class:`~matplotlib.figure.Figure`). The -standard use is to create a :class:`~matplotlib.figure.Figure` instance, use -the ``Figure`` to create one or more :class:`~matplotlib.axes.Axes` or -:class:`~matplotlib.axes.Subplot` instances, and use the ``Axes`` instance -helper methods to create the primitives. In the example below, we create a -``Figure`` instance using :func:`matplotlib.pyplot.figure`, which is a -convenience method for instantiating ``Figure`` instances and connecting them -with your user interface or drawing toolkit ``FigureCanvas``. As we will -discuss below, this is not necessary -- you can work directly with PostScript, -PDF Gtk+, or wxPython ``FigureCanvas`` instances, instantiate your ``Figures`` -directly and connect them yourselves -- but since we are focusing here on the -``Artist`` API we'll let :mod:`~matplotlib.pyplot` handle some of those details -for us:: - - import matplotlib.pyplot as plt - fig = plt.figure() - ax = fig.add_subplot(2,1,1) # two rows, one column, first plot - -The :class:`~matplotlib.axes.Axes` is probably the most important -class in the matplotlib API, and the one you will be working with most -of the time. This is because the ``Axes`` is the plotting area into -which most of the objects go, and the ``Axes`` has many special helper -methods (:meth:`~matplotlib.axes.Axes.plot`, -:meth:`~matplotlib.axes.Axes.text`, -:meth:`~matplotlib.axes.Axes.hist`, -:meth:`~matplotlib.axes.Axes.imshow`) to create the most common -graphics primitives (:class:`~matplotlib.lines.Line2D`, -:class:`~matplotlib.text.Text`, -:class:`~matplotlib.patches.Rectangle`, -:class:`~matplotlib.image.Image`, respectively). These helper methods -will take your data (e.g., ``numpy`` arrays and strings) and create -primitive ``Artist`` instances as needed (e.g., ``Line2D``), add them to -the relevant containers, and draw them when requested. Most of you -are probably familiar with the :class:`~matplotlib.axes.Subplot`, -which is just a special case of an ``Axes`` that lives on a regular -rows by columns grid of ``Subplot`` instances. If you want to create -an ``Axes`` at an arbitrary location, simply use the -:meth:`~matplotlib.figure.Figure.add_axes` method which takes a list -of ``[left, bottom, width, height]`` values in 0-1 relative figure -coordinates:: - - fig2 = plt.figure() - ax2 = fig2.add_axes([0.15, 0.1, 0.7, 0.3]) - -Continuing with our example:: - - import numpy as np - t = np.arange(0.0, 1.0, 0.01) - s = np.sin(2*np.pi*t) - line, = ax.plot(t, s, color='blue', lw=2) - -In this example, ``ax`` is the ``Axes`` instance created by the -``fig.add_subplot`` call above (remember ``Subplot`` is just a -subclass of ``Axes``) and when you call ``ax.plot``, it creates a -``Line2D`` instance and adds it to the :attr:`Axes.lines -` list. In the interactive `ipython -`_ session below, you can see that the -``Axes.lines`` list is length one and contains the same line that was -returned by the ``line, = ax.plot...`` call: - -.. sourcecode:: ipython - - In [101]: ax.lines[0] - Out[101]: - - In [102]: line - Out[102]: - -If you make subsequent calls to ``ax.plot`` (and the hold state is "on" -which is the default) then additional lines will be added to the list. -You can remove lines later simply by calling the list methods; either -of these will work:: - - del ax.lines[0] - ax.lines.remove(line) # one or the other, not both! - -The Axes also has helper methods to configure and decorate the x-axis -and y-axis tick, tick labels and axis labels:: - - xtext = ax.set_xlabel('my xdata') # returns a Text instance - ytext = ax.set_ylabel('my ydata') - -When you call :meth:`ax.set_xlabel `, -it passes the information on the :class:`~matplotlib.text.Text` -instance of the :class:`~matplotlib.axis.XAxis`. Each ``Axes`` -instance contains an :class:`~matplotlib.axis.XAxis` and a -:class:`~matplotlib.axis.YAxis` instance, which handle the layout and -drawing of the ticks, tick labels and axis labels. - -.. I'm commenting this out, since the new Sphinx cross-references -.. sort of take care of this above - MGD - -.. Here are the most important matplotlib modules that contain the -.. classes referenced above - -.. =============== ================== -.. Artist Module -.. =============== ================== -.. Artist matplotlib.artist -.. Rectangle matplotlib.patches -.. Line2D matplotlib.lines -.. Axes matplotlib.axes -.. XAxis and YAxis matplotlib.axis -.. Figure matplotlib.figure -.. Text matplotlib.text -.. =============== ================== - -Try creating the figure below. - -.. figure:: ../gallery/pyplots/images/sphx_glr_fig_axes_labels_simple_001.png - :target: ../gallery/pyplots/fig_axes_labels_simple.html - :align: center - :scale: 50 - - Fig Axes Labels Simple - -.. _customizing-artists: - -Customizing your objects -======================== - -Every element in the figure is represented by a matplotlib -:class:`~matplotlib.artist.Artist`, and each has an extensive list of -properties to configure its appearance. The figure itself contains a -:class:`~matplotlib.patches.Rectangle` exactly the size of the figure, -which you can use to set the background color and transparency of the -figures. Likewise, each :class:`~matplotlib.axes.Axes` bounding box -(the standard white box with black edges in the typical matplotlib -plot, has a ``Rectangle`` instance that determines the color, -transparency, and other properties of the Axes. These instances are -stored as member variables :attr:`Figure.patch -` and :attr:`Axes.patch -` ("Patch" is a name inherited from -MATLAB, and is a 2D "patch" of color on the figure, e.g., rectangles, -circles and polygons). Every matplotlib ``Artist`` has the following -properties - -========== ================================================================================ -Property Description -========== ================================================================================ -alpha The transparency - a scalar from 0-1 -animated A boolean that is used to facilitate animated drawing -axes The axes that the Artist lives in, possibly None -clip_box The bounding box that clips the Artist -clip_on Whether clipping is enabled -clip_path The path the artist is clipped to -contains A picking function to test whether the artist contains the pick point -figure The figure instance the artist lives in, possibly None -label A text label (e.g., for auto-labeling) -picker A python object that controls object picking -transform The transformation -visible A boolean whether the artist should be drawn -zorder A number which determines the drawing order -rasterized Boolean; Turns vectors into rastergraphics: (for compression & eps transparency) -========== ================================================================================ - -Each of the properties is accessed with an old-fashioned setter or -getter (yes we know this irritates Pythonistas and we plan to support -direct access via properties or traits but it hasn't been done yet). -For example, to multiply the current alpha by a half:: - - a = o.get_alpha() - o.set_alpha(0.5*a) - -If you want to set a number of properties at once, you can also use -the ``set`` method with keyword arguments. For example:: - - o.set(alpha=0.5, zorder=2) - -If you are working interactively at the python shell, a handy way to -inspect the ``Artist`` properties is to use the -:func:`matplotlib.artist.getp` function (simply -:func:`~matplotlib.pylab.getp` in pylab), which lists the properties -and their values. This works for classes derived from ``Artist`` as -well, e.g., ``Figure`` and ``Rectangle``. Here are the ``Figure`` rectangle -properties mentioned above: - -.. sourcecode:: ipython - - In [149]: matplotlib.artist.getp(fig.patch) - alpha = 1.0 - animated = False - antialiased or aa = True - axes = None - clip_box = None - clip_on = False - clip_path = None - contains = None - edgecolor or ec = w - facecolor or fc = 0.75 - figure = Figure(8.125x6.125) - fill = 1 - hatch = None - height = 1 - label = - linewidth or lw = 1.0 - picker = None - transform = - verts = ((0, 0), (0, 1), (1, 1), (1, 0)) - visible = True - width = 1 - window_extent = - x = 0 - y = 0 - zorder = 1 - -.. TODO: Update these URLs - -The docstrings for all of the classes also contain the ``Artist`` -properties, so you can consult the interactive "help" or the -:ref:`artist-api` for a listing of properties for a given object. - -.. _object-containers: - -Object containers -================= - - -Now that we know how to inspect and set the properties of a given -object we want to configure, we need to know how to get at that object. -As mentioned in the introduction, there are two kinds of objects: -primitives and containers. The primitives are usually the things you -want to configure (the font of a :class:`~matplotlib.text.Text` -instance, the width of a :class:`~matplotlib.lines.Line2D`) although -the containers also have some properties as well -- for example the -:class:`~matplotlib.axes.Axes` :class:`~matplotlib.artist.Artist` is a -container that contains many of the primitives in your plot, but it -also has properties like the ``xscale`` to control whether the xaxis -is 'linear' or 'log'. In this section we'll review where the various -container objects store the ``Artists`` that you want to get at. - -.. _figure-container: - -Figure container -================ - -The top level container ``Artist`` is the -:class:`matplotlib.figure.Figure`, and it contains everything in the -figure. The background of the figure is a -:class:`~matplotlib.patches.Rectangle` which is stored in -:attr:`Figure.patch `. As -you add subplots (:meth:`~matplotlib.figure.Figure.add_subplot`) and -axes (:meth:`~matplotlib.figure.Figure.add_axes`) to the figure -these will be appended to the :attr:`Figure.axes -`. These are also returned by the -methods that create them: - -.. sourcecode:: ipython - - In [156]: fig = plt.figure() - - In [157]: ax1 = fig.add_subplot(211) - - In [158]: ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3]) - - In [159]: ax1 - Out[159]: - - In [160]: print fig.axes - [, ] - -Because the figure maintains the concept of the "current axes" (see -:meth:`Figure.gca ` and -:meth:`Figure.sca `) to support the -pylab/pyplot state machine, you should not insert or remove axes -directly from the axes list, but rather use the -:meth:`~matplotlib.figure.Figure.add_subplot` and -:meth:`~matplotlib.figure.Figure.add_axes` methods to insert, and the -:meth:`~matplotlib.figure.Figure.delaxes` method to delete. You are -free however, to iterate over the list of axes or index into it to get -access to ``Axes`` instances you want to customize. Here is an -example which turns all the axes grids on:: - - for ax in fig.axes: - ax.grid(True) - - -The figure also has its own text, lines, patches and images, which you -can use to add primitives directly. The default coordinate system for -the ``Figure`` will simply be in pixels (which is not usually what you -want) but you can control this by setting the transform property of -the ``Artist`` you are adding to the figure. - -.. TODO: Is that still true? - -More useful is "figure coordinates" where (0, 0) is the bottom-left of -the figure and (1, 1) is the top-right of the figure which you can -obtain by setting the ``Artist`` transform to :attr:`fig.transFigure -`: - -.. sourcecode:: ipython - - In [191]: fig = plt.figure() - - In [192]: l1 = matplotlib.lines.Line2D([0, 1], [0, 1], - transform=fig.transFigure, figure=fig) - - In [193]: l2 = matplotlib.lines.Line2D([0, 1], [1, 0], - transform=fig.transFigure, figure=fig) - - In [194]: fig.lines.extend([l1, l2]) - - In [195]: fig.canvas.draw() - -.. figure:: ../gallery/pyplots/images/sphx_glr_fig_x_001.png - :target: ../gallery/pyplots/fig_x.html - :align: center - :scale: 50 - - Fig X - - -Here is a summary of the Artists the figure contains - -.. TODO: Add xrefs to this table - -================ =============================================================== -Figure attribute Description -================ =============================================================== -axes A list of Axes instances (includes Subplot) -patch The Rectangle background -images A list of FigureImages patches - useful for raw pixel display -legends A list of Figure Legend instances (different from Axes.legends) -lines A list of Figure Line2D instances (rarely used, see Axes.lines) -patches A list of Figure patches (rarely used, see Axes.patches) -texts A list Figure Text instances -================ =============================================================== - -.. _axes-container: - -Axes container -============== - -The :class:`matplotlib.axes.Axes` is the center of the matplotlib -universe -- it contains the vast majority of all the ``Artists`` used -in a figure with many helper methods to create and add these -``Artists`` to itself, as well as helper methods to access and -customize the ``Artists`` it contains. Like the -:class:`~matplotlib.figure.Figure`, it contains a -:class:`~matplotlib.patches.Patch` -:attr:`~matplotlib.axes.Axes.patch` which is a -:class:`~matplotlib.patches.Rectangle` for Cartesian coordinates and a -:class:`~matplotlib.patches.Circle` for polar coordinates; this patch -determines the shape, background and border of the plotting region:: - - ax = fig.add_subplot(111) - rect = ax.patch # a Rectangle instance - rect.set_facecolor('green') - -When you call a plotting method, e.g., the canonical -:meth:`~matplotlib.axes.Axes.plot` and pass in arrays or lists of -values, the method will create a :meth:`matplotlib.lines.Line2D` -instance, update the line with all the ``Line2D`` properties passed as -keyword arguments, add the line to the :attr:`Axes.lines -` container, and returns it to you: - -.. sourcecode:: ipython - - In [213]: x, y = np.random.rand(2, 100) - - In [214]: line, = ax.plot(x, y, '-', color='blue', linewidth=2) - -``plot`` returns a list of lines because you can pass in multiple x, y -pairs to plot, and we are unpacking the first element of the length -one list into the line variable. The line has been added to the -``Axes.lines`` list: - -.. sourcecode:: ipython - - In [229]: print ax.lines - [] - -Similarly, methods that create patches, like -:meth:`~matplotlib.axes.Axes.bar` creates a list of rectangles, will -add the patches to the :attr:`Axes.patches -` list: - -.. sourcecode:: ipython - - In [233]: n, bins, rectangles = ax.hist(np.random.randn(1000), 50, facecolor='yellow') - - In [234]: rectangles - Out[234]: - - In [235]: print len(ax.patches) - -You should not add objects directly to the ``Axes.lines`` or -``Axes.patches`` lists unless you know exactly what you are doing, -because the ``Axes`` needs to do a few things when it creates and adds -an object. It sets the figure and axes property of the ``Artist``, as -well as the default ``Axes`` transformation (unless a transformation -is set). It also inspects the data contained in the ``Artist`` to -update the data structures controlling auto-scaling, so that the view -limits can be adjusted to contain the plotted data. You can, -nonetheless, create objects yourself and add them directly to the -``Axes`` using helper methods like -:meth:`~matplotlib.axes.Axes.add_line` and -:meth:`~matplotlib.axes.Axes.add_patch`. Here is an annotated -interactive session illustrating what is going on: - -.. sourcecode:: ipython - - In [261]: fig = plt.figure() - - In [262]: ax = fig.add_subplot(111) - - # create a rectangle instance - In [263]: rect = matplotlib.patches.Rectangle( (1,1), width=5, height=12) - - # by default the axes instance is None - In [264]: print rect.get_axes() - None - - # and the transformation instance is set to the "identity transform" - In [265]: print rect.get_transform() - - - # now we add the Rectangle to the Axes - In [266]: ax.add_patch(rect) - - # and notice that the ax.add_patch method has set the axes - # instance - In [267]: print rect.get_axes() - Axes(0.125,0.1;0.775x0.8) - - # and the transformation has been set too - In [268]: print rect.get_transform() - - - # the default axes transformation is ax.transData - In [269]: print ax.transData - - - # notice that the xlimits of the Axes have not been changed - In [270]: print ax.get_xlim() - (0.0, 1.0) - - # but the data limits have been updated to encompass the rectangle - In [271]: print ax.dataLim.bounds - (1.0, 1.0, 5.0, 12.0) - - # we can manually invoke the auto-scaling machinery - In [272]: ax.autoscale_view() - - # and now the xlim are updated to encompass the rectangle - In [273]: print ax.get_xlim() - (1.0, 6.0) - - # we have to manually force a figure draw - In [274]: ax.figure.canvas.draw() - - -There are many, many ``Axes`` helper methods for creating primitive -``Artists`` and adding them to their respective containers. The table -below summarizes a small sampling of them, the kinds of ``Artist`` they -create, and where they store them - -============================== ==================== ======================= -Helper method Artist Container -============================== ==================== ======================= -ax.annotate - text annotations Annotate ax.texts -ax.bar - bar charts Rectangle ax.patches -ax.errorbar - error bar plots Line2D and Rectangle ax.lines and ax.patches -ax.fill - shared area Polygon ax.patches -ax.hist - histograms Rectangle ax.patches -ax.imshow - image data AxesImage ax.images -ax.legend - axes legends Legend ax.legends -ax.plot - xy plots Line2D ax.lines -ax.scatter - scatter charts PolygonCollection ax.collections -ax.text - text Text ax.texts -============================== ==================== ======================= - - -In addition to all of these ``Artists``, the ``Axes`` contains two -important ``Artist`` containers: the :class:`~matplotlib.axis.XAxis` -and :class:`~matplotlib.axis.YAxis`, which handle the drawing of the -ticks and labels. These are stored as instance variables -:attr:`~matplotlib.axes.Axes.xaxis` and -:attr:`~matplotlib.axes.Axes.yaxis`. The ``XAxis`` and ``YAxis`` -containers will be detailed below, but note that the ``Axes`` contains -many helper methods which forward calls on to the -:class:`~matplotlib.axis.Axis` instances so you often do not need to -work with them directly unless you want to. For example, you can set -the font color of the ``XAxis`` ticklabels using the ``Axes`` helper -method:: - - for label in ax.get_xticklabels(): - label.set_color('orange') - -Below is a summary of the Artists that the Axes contains - -============== ====================================== -Axes attribute Description -============== ====================================== -artists A list of Artist instances -patch Rectangle instance for Axes background -collections A list of Collection instances -images A list of AxesImage -legends A list of Legend instances -lines A list of Line2D instances -patches A list of Patch instances -texts A list of Text instances -xaxis matplotlib.axis.XAxis instance -yaxis matplotlib.axis.YAxis instance -============== ====================================== - -.. _axis-container: - -Axis containers -=============== - -The :class:`matplotlib.axis.Axis` instances handle the drawing of the -tick lines, the grid lines, the tick labels and the axis label. You -can configure the left and right ticks separately for the y-axis, and -the upper and lower ticks separately for the x-axis. The ``Axis`` -also stores the data and view intervals used in auto-scaling, panning -and zooming, as well as the :class:`~matplotlib.ticker.Locator` and -:class:`~matplotlib.ticker.Formatter` instances which control where -the ticks are placed and how they are represented as strings. - -Each ``Axis`` object contains a :attr:`~matplotlib.axis.Axis.label` attribute -(this is what :mod:`~matplotlib.pylab` modifies in calls to -:func:`~matplotlib.pylab.xlabel` and :func:`~matplotlib.pylab.ylabel`) as well -as a list of major and minor ticks. The ticks are -:class:`~matplotlib.axis.XTick` and :class:`~matplotlib.axis.YTick` instances, -which contain the actual line and text primitives that render the ticks and -ticklabels. Because the ticks are dynamically created as needed (e.g., when -panning and zooming), you should access the lists of major and minor ticks -through their accessor methods :meth:`~matplotlib.axis.Axis.get_major_ticks` -and :meth:`~matplotlib.axis.Axis.get_minor_ticks`. Although the ticks contain -all the primitives and will be covered below, ``Axis`` instances have accessor -methods that return the tick lines, tick labels, tick locations etc.: - -.. sourcecode:: ipython - - In [285]: axis = ax.xaxis - - In [286]: axis.get_ticklocs() - Out[286]: array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]) - - In [287]: axis.get_ticklabels() - Out[287]: - - # note there are twice as many ticklines as labels because by - # default there are tick lines at the top and bottom but only tick - # labels below the xaxis; this can be customized - In [288]: axis.get_ticklines() - Out[288]: - - # by default you get the major ticks back - In [291]: axis.get_ticklines() - Out[291]: - - # but you can also ask for the minor ticks - In [292]: axis.get_ticklines(minor=True) - Out[292]: - -Here is a summary of some of the useful accessor methods of the ``Axis`` -(these have corresponding setters where useful, such as -set_major_formatter) - -====================== ========================================================= -Accessor method Description -====================== ========================================================= -get_scale The scale of the axis, e.g., 'log' or 'linear' -get_view_interval The interval instance of the axis view limits -get_data_interval The interval instance of the axis data limits -get_gridlines A list of grid lines for the Axis -get_label The axis label - a Text instance -get_ticklabels A list of Text instances - keyword minor=True|False -get_ticklines A list of Line2D instances - keyword minor=True|False -get_ticklocs A list of Tick locations - keyword minor=True|False -get_major_locator The matplotlib.ticker.Locator instance for major ticks -get_major_formatter The matplotlib.ticker.Formatter instance for major ticks -get_minor_locator The matplotlib.ticker.Locator instance for minor ticks -get_minor_formatter The matplotlib.ticker.Formatter instance for minor ticks -get_major_ticks A list of Tick instances for major ticks -get_minor_ticks A list of Tick instances for minor ticks -grid Turn the grid on or off for the major or minor ticks -====================== ========================================================= - -Here is an example, not recommended for its beauty, which customizes -the axes and tick properties - -.. figure:: ../gallery/pyplots/images/sphx_glr_fig_axes_customize_simple_001.png - :target: ../gallery/pyplots/fig_axes_customize_simple.html - :align: center - :scale: 50 - - Fig Axes Customize Simple - - -.. _tick-container: - -Tick containers -=============== - -The :class:`matplotlib.axis.Tick` is the final container object in our -descent from the :class:`~matplotlib.figure.Figure` to the -:class:`~matplotlib.axes.Axes` to the :class:`~matplotlib.axis.Axis` -to the :class:`~matplotlib.axis.Tick`. The ``Tick`` contains the tick -and grid line instances, as well as the label instances for the upper -and lower ticks. Each of these is accessible directly as an attribute -of the ``Tick``. In addition, there are boolean variables that determine -whether the upper labels and ticks are on for the x-axis and whether -the right labels and ticks are on for the y-axis. - -============== ========================================================== -Tick attribute Description -============== ========================================================== -tick1line Line2D instance -tick2line Line2D instance -gridline Line2D instance -label1 Text instance -label2 Text instance -gridOn boolean which determines whether to draw the gridline -tick1On boolean which determines whether to draw the 1st tickline -tick2On boolean which determines whether to draw the 2nd tickline -label1On boolean which determines whether to draw the 1st tick label -label2On boolean which determines whether to draw the 2nd tick label -============== ========================================================== - -Here is an example which sets the formatter for the right side ticks with -dollar signs and colors them green on the right side of the yaxis - -.. figure:: ../gallery/pyplots/images/sphx_glr_dollar_ticks_001.png - :target: ../gallery/pyplots/dollar_ticks.html - :align: center - :scale: 50 - - Dollar Ticks - - - - - diff --git a/doc/users/color_index.rst b/doc/users/color_index.rst deleted file mode 100644 index 84238a040f0a..000000000000 --- a/doc/users/color_index.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. _color-index: - -======== - Colors -======== - -.. htmlonly:: - - :Release: |version| - :Date: |today| - -.. toctree:: - - colors.rst - colormaps.rst - colormapnorms.rst diff --git a/doc/users/colormapnorms.rst b/doc/users/colormapnorms.rst deleted file mode 100644 index 2e75ea387fbf..000000000000 --- a/doc/users/colormapnorms.rst +++ /dev/null @@ -1,162 +0,0 @@ -.. _colormapnorm-tutorial: - -Colormap Normalization -====================== - -Objects that use colormaps by default linearly map the colors in the -colormap from data values *vmin* to *vmax*. For example:: - - pcm = ax.pcolormesh(x, y, Z, vmin=-1., vmax=1., cmap='RdBu_r') - -will map the data in *Z* linearly from -1 to +1, so *Z=0* will -give a color at the center of the colormap *RdBu_r* (white in this -case). - -Matplotlib does this mapping in two steps, with a normalization from -[0,1] occurring first, and then mapping onto the indices in the -colormap. Normalizations are classes defined in the -:func:`matplotlib.colors` module. The default, linear normalization is -:func:`matplotlib.colors.Normalize`. - -Artists that map data to color pass the arguments *vmin* and *vmax* to -construct a :func:`matplotlib.colors.Normalize` instance, then call it: - -.. ipython:: - - In [1]: import matplotlib as mpl - - In [2]: norm = mpl.colors.Normalize(vmin=-1.,vmax=1.) - - In [3]: norm(0.) - Out[3]: 0.5 - -However, there are sometimes cases where it is useful to map data to -colormaps in a non-linear fashion. - -Logarithmic ------------ - -One of the most common transformations is to plot data by taking -its logarithm (to the base-10). This transformation is useful to -display changes across disparate scales. Using :func:`colors.LogNorm` -normalizes the data via :math:`log_{10}`. In the example below, -there are two bumps, one much smaller than the other. Using -:func:`colors.LogNorm`, the shape and location of each bump can clearly -be seen: - -.. figure:: ../gallery/userdemo/images/sphx_glr_colormap_normalizations_lognorm_001.png - :target: ../gallery/userdemo/colormap_normalizations_lognorm.html - :align: center - :scale: 50 - - Colormap Normalizations Lognorm - -Symmetric logarithmic ---------------------- - -Similarly, it sometimes happens that there is data that is positive -and negative, but we would still like a logarithmic scaling applied to -both. In this case, the negative numbers are also scaled -logarithmically, and mapped to smaller numbers; e.g., if `vmin=-vmax`, -then they the negative numbers are mapped from 0 to 0.5 and the -positive from 0.5 to 1. - -Since the logarithm of values close to zero tends toward infinity, a -small range around zero needs to be mapped linearly. The parameter -*linthresh* allows the user to specify the size of this range -(-*linthresh*, *linthresh*). The size of this range in the colormap is -set by *linscale*. When *linscale* == 1.0 (the default), the space used -for the positive and negative halves of the linear range will be equal -to one decade in the logarithmic range. - -.. figure:: ../gallery/userdemo/images/sphx_glr_colormap_normalizations_symlognorm_001.png - :target: ../gallery/userdemo/colormap_normalizations_symlognorm.html - :align: center - :scale: 50 - - Colormap Normalizations Symlognorm - -Power-law ---------- - -Sometimes it is useful to remap the colors onto a power-law -relationship (i.e. :math:`y=x^{\gamma}`, where :math:`\gamma` is the -power). For this we use the :func:`colors.PowerNorm`. It takes as an -argument *gamma* (*gamma* == 1.0 will just yield the default linear -normalization): - -.. note:: - - There should probably be a good reason for plotting the data using - this type of transformation. Technical viewers are used to linear - and logarithmic axes and data transformations. Power laws are less - common, and viewers should explicitly be made aware that they have - been used. - - -.. figure:: ../gallery/userdemo/images/sphx_glr_colormap_normalizations_power_001.png - :target: ../gallery/userdemo/colormap_normalizations_power.html - :align: center - :scale: 50 - - Colormap Normalizations Power - -Discrete bounds ---------------- - -Another normaization that comes with matplolib is -:func:`colors.BoundaryNorm`. In addition to *vmin* and *vmax*, this -takes as arguments boundaries between which data is to be mapped. The -colors are then linearly distributed between these "bounds". For -instance: - -.. ipython:: - - In [2]: import matplotlib.colors as colors - - In [3]: bounds = np.array([-0.25, -0.125, 0, 0.5, 1]) - - In [4]: norm = colors.BoundaryNorm(boundaries=bounds, ncolors=4) - - In [5]: print(norm([-0.2,-0.15,-0.02, 0.3, 0.8, 0.99])) - [0 0 1 2 3 3] - -Note unlike the other norms, this norm returns values from 0 to *ncolors*-1. - -.. figure:: ../gallery/userdemo/images/sphx_glr_colormap_normalizations_bounds_001.png - :target: ../gallery/userdemo/colormap_normalizations_bounds.html - :align: center - :scale: 50 - - Colormap Normalizations Bounds - - -Custom normalization: Two linear ranges ---------------------------------------- - -It is possible to define your own normalization. In the following -example, we modify :func:`colors:SymLogNorm` to use different linear -maps for the negative data values and the positive. (Note that this -example is simple, and does not validate inputs or account for complex -cases such as masked data) - -.. note:: - This may appear soon as :func:`colors.OffsetNorm`. - - As above, non-symmetric mapping of data to color is non-standard - practice for quantitative data, and should only be used advisedly. A - practical example is having an ocean/land colormap where the land and - ocean data span different ranges. - -.. figure:: ../gallery/userdemo/images/sphx_glr_colormap_normalizations_custom_001.png - :target: ../gallery/userdemo/colormap_normalizations_custom.html - :align: center - :scale: 50 - - Colormap Normalizations Custom - - - - - - diff --git a/doc/users/colormaps.rst b/doc/users/colormaps.rst deleted file mode 100644 index 6365f3acfbc2..000000000000 --- a/doc/users/colormaps.rst +++ /dev/null @@ -1,206 +0,0 @@ -.. _colormaps: - -****************** -Choosing Colormaps -****************** - - -Overview -======== - -The idea behind choosing a good colormap is to find a good representation in 3D -colorspace for your data set. The best colormap for any given data set depends -on many things including: - -- Whether representing form or metric data ([Ware]_) - -- Your knowledge of the data set (*e.g.*, is there a critical value - from which the other values deviate?) - -- If there is an intuitive color scheme for the parameter you are plotting - -- If there is a standard in the field the audience may be expecting - -For many applications, a perceptually uniform colormap is the best -choice --- one in which equal steps in data are perceived as equal -steps in the color space. Researchers have found that the human brain -perceives changes in the lightness parameter as changes in the data -much better than, for example, changes in hue. Therefore, colormaps -which have monotonically increasing lightness through the colormap -will be better interpreted by the viewer. A wonderful example of -perceptually uniform colormaps is [colorcet]_. - -Color can be represented in 3D space in various ways. One way to represent color -is using CIELAB. In CIELAB, color space is represented by lightness, -:math:`L^*`; red-green, :math:`a^*`; and yellow-blue, :math:`b^*`. The lightness -parameter :math:`L^*` can then be used to learn more about how the matplotlib -colormaps will be perceived by viewers. - -An excellent starting resource for learning about human perception of colormaps -is from [IBM]_. - - -Classes of colormaps -==================== - -Colormaps are often split into several categories based on their function (see, -*e.g.*, [Moreland]_): - -1. Sequential: change in lightness and often saturation of color - incrementally, often using a single hue; should be used for - representing information that has ordering. - -2. Diverging: change in lightness and possibly saturation of two - different colors that meet in the middle at an unsaturated color; - should be used when the information being plotted has a critical - middle value, such as topography or when the data deviates around - zero. - -3. Qualitative: often are miscellaneous colors; should be used to - represent information which does not have ordering or - relationships. - - -Lightness of matplotlib colormaps -================================= - -Here we examine the lightness values of the matplotlib colormaps. Note that some -documentation on the colormaps is available ([list-colormaps]_). - -Sequential ----------- - -For the Sequential plots, the lightness value increases monotonically through -the colormaps. This is good. Some of the :math:`L^*` values in the colormaps -span from 0 to 100 (binary and the other grayscale), and others start around -:math:`L^*=20`. Those that have a smaller range of :math:`L^*` will accordingly -have a smaller perceptual range. Note also that the :math:`L^*` function varies -amongst the colormaps: some are approximately linear in :math:`L^*` and others -are more curved. - -Sequential2 ------------ - -Many of the :math:`L^*` values from the Sequential2 plots are monotonically -increasing, but some (autumn, cool, spring, and winter) plateau or even go both -up and down in :math:`L^*` space. Others (afmhot, copper, gist_heat, and hot) -have kinks in the :math:`L^*` functions. Data that is being represented in a -region of the colormap that is at a plateau or kink will lead to a perception of -banding of the data in those values in the colormap (see [mycarta-banding]_ for -an excellent example of this). - -Diverging ---------- - -For the Diverging maps, we want to have monotonically increasing :math:`L^*` -values up to a maximum, which should be close to :math:`L^*=100`, followed by -monotonically decreasing :math:`L^*` values. We are looking for approximately -equal minimum :math:`L^*` values at opposite ends of the colormap. By these -measures, BrBG and RdBu are good options. coolwarm is a good option, but it -doesn't span a wide range of :math:`L^*` values (see grayscale section below). - -Qualitative ------------ - -Qualitative colormaps are not aimed at being perceptual maps, but looking at the -lightness parameter can verify that for us. The :math:`L^*` values move all over -the place throughout the colormap, and are clearly not monotonically increasing. -These would not be good options for use as perceptual colormaps. - -Miscellaneous -------------- - -Some of the miscellaneous colormaps have particular uses for which -they have been created. For example, gist_earth, ocean, and terrain -all seem to be created for plotting topography (green/brown) and water -depths (blue) together. We would expect to see a divergence in these -colormaps, then, but multiple kinks may not be ideal, such as in -gist_earth and terrain. CMRmap was created to convert well to -grayscale, though it does appear to have some small kinks in -:math:`L^*`. cubehelix was created to vary smoothly in both lightness -and hue, but appears to have a small hump in the green hue area. - -The often-used jet colormap is included in this set of colormaps. We can see -that the :math:`L^*` values vary widely throughout the colormap, making it a -poor choice for representing data for viewers to see perceptually. See an -extension on this idea at [mycarta-jet]_. - -.. figure:: ../gallery/color/images/sphx_glr_lightness_001.png - :target: ../gallery/color/lightness.html - :align: center - :scale: 50 - - Lightness - -Grayscale conversion -==================== - -It is important to pay attention to conversion to grayscale for color -plots, since they may be printed on black and white printers. If not -carefully considered, your readers may end up with indecipherable -plots because the grayscale changes unpredictably through the -colormap. - -Conversion to grayscale is done in many different ways [bw]_. Some of the better -ones use a linear combination of the rgb values of a pixel, but weighted -according to how we perceive color intensity. A nonlinear method of conversion -to grayscale is to use the :math:`L^*` values of the pixels. In general, similar -principles apply for this question as they do for presenting one's information -perceptually; that is, if a colormap is chosen that is monotonically increasing -in :math:`L^*` values, it will print in a reasonable manner to grayscale. - -With this in mind, we see that the Sequential colormaps have reasonable -representations in grayscale. Some of the Sequential2 colormaps have decent -enough grayscale representations, though some (autumn, spring, summer, winter) -have very little grayscale change. If a colormap like this was used in a plot -and then the plot was printed to grayscale, a lot of the information may map to -the same gray values. The Diverging colormaps mostly vary from darker gray on -the outer edges to white in the middle. Some (PuOr and seismic) have noticably -darker gray on one side than the other and therefore are not very symmetric. -coolwarm has little range of gray scale and would print to a more uniform plot, -losing a lot of detail. Note that overlaid, labeled contours could help -differentiate between one side of the colormap vs. the other since color cannot -be used once a plot is printed to grayscale. Many of the Qualitative and -Miscellaneous colormaps, such as Accent, hsv, and jet, change from darker to -lighter and back to darker gray throughout the colormap. This would make it -impossible for a viewer to interpret the information in a plot once it is -printed in grayscale. - -.. figure:: ../gallery/color/images/sphx_glr_grayscale_001.png - :target: ../gallery/color/grayscale.html - :align: center - :scale: 50 - - Grayscale - - -Color vision deficiencies -========================= - -There is a lot of information available about color blindness (*e.g.*, -[colorblindness]_). Additionally, there are tools available to convert images to -how they look for different types of color vision deficiencies (*e.g.*, -[vischeck]_). - -The most common form of color vision deficiency involves differentiating between -red and green. Thus, avoiding colormaps with both red and green will avoid many -problems in general. - - -References -========== - -.. [colorcet] https://github.com/bokeh/colorcet -.. [Ware] http://ccom.unh.edu/sites/default/files/publications/Ware_1988_CGA_Color_sequences_univariate_maps.pdf -.. [Moreland] http://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf -.. [list-colormaps] https://gist.github.com/endolith/2719900#id7 -.. [mycarta-banding] https://mycarta.wordpress.com/2012/10/14/the-rainbow-is-deadlong-live-the-rainbow-part-4-cie-lab-heated-body/ -.. [mycarta-jet] https://mycarta.wordpress.com/2012/10/06/the-rainbow-is-deadlong-live-the-rainbow-part-3/ -.. [mycarta-lablinear] https://mycarta.wordpress.com/2012/12/06/the-rainbow-is-deadlong-live-the-rainbow-part-5-cie-lab-linear-l-rainbow/ -.. [mycarta-cubelaw] https://mycarta.wordpress.com/2013/02/21/perceptual-rainbow-palette-the-method/ -.. [bw] http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/ -.. [colorblindness] http://www.color-blindness.com/ -.. [vischeck] http://www.vischeck.com/vischeck/ -.. [IBM] http://www.research.ibm.com/people/l/lloydt/color/color.HTM - - diff --git a/doc/users/colors.rst b/doc/users/colors.rst deleted file mode 100644 index d08861bccec0..000000000000 --- a/doc/users/colors.rst +++ /dev/null @@ -1,116 +0,0 @@ -.. _colors: - -***************** -Specifying Colors -***************** - -In almost all places in matplotlib where a color can be specified by the user -it can be provided as: - -* an RGB or RGBA tuple of float values in ``[0, 1]`` - (e.g., ``(0.1, 0.2, 0.5)`` or ``(0.1, 0.2, 0.5, 0.3)``) -* a hex RGB or RGBA string (e.g., ``'#0F0F0F'`` or ``'#0F0F0F0F'``) -* a string representation of a float value in ``[0, 1]`` - inclusive for gray level (e.g., ``'0.5'``) -* one of ``{'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'}`` -* a X11/CSS4 color name -* a name from the `xkcd color survey `__ - prefixed with ``'xkcd:'`` (e.g., ``'xkcd:sky blue'``) -* one of ``{'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'}`` -* one of ``{'tab:blue', 'tab:orange', 'tab:green', - 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', - 'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from the - 'T10' categorical palette (which is the default color cycle). - -All string specifications of color are case-insensitive. - - -``'CN'`` color selection ------------------------- - -Color can be specified by a string matching the regex ``C[0-9]``. -This can be passed any place that a color is currently accepted and -can be used as a 'single character color' in format-string to -`matplotlib.Axes.plot`. - -The single digit is the index into the default property cycle -(``matplotlib.rcParams['axes.prop_cycle']``). If the property cycle does not -include ``'color'`` then black is returned. The color is evaluated when the -artist is created. For example, - -.. plot:: - :include-source: True - - import numpy as np - import matplotlib.pyplot as plt - import matplotlib as mpl - th = np.linspace(0, 2*np.pi, 128) - - def demo(sty): - mpl.style.use(sty) - fig, ax = plt.subplots(figsize=(3, 3)) - - ax.set_title('style: {!r}'.format(sty), color='C0') - - ax.plot(th, np.cos(th), 'C1', label='C1') - ax.plot(th, np.sin(th), 'C2', label='C2') - ax.legend() - - demo('default') - demo('seaborn') - -will use the first color for the title and then plot using the second -and third colors of each style's ``mpl.rcParams['axes.prop_cycle']``. - - -xkcd v X11/CSS4 ---------------- - -The xkcd colors are derived from a user survey conducted by the -webcomic xkcd. `Details of the survey are available on the xkcd blog -`__. - -Out of 148 colors in the CSS color list, there are 95 name collisions -between the X11/CSS4 names and the xkcd names, all but 3 of which have -different hex values. For example ``'blue'`` maps to ``'#0000FF'`` -where as ``'xkcd:blue'`` maps to ``'#0343DF'``. Due to these name -collisions all of the xkcd colors have ``'xkcd:'`` prefixed. As noted in -the blog post, while it might be interesting to re-define the X11/CSS4 names -based on such a survey, we do not do so unilaterally. - -The name collisions are shown in the table below; the color names -where the hex values agree are shown in bold. - - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib._color_data as mcd - import matplotlib.patches as mpatch - - overlap = {name for name in mcd.CSS4_COLORS - if "xkcd:" + name in mcd.XKCD_COLORS} - - fig = plt.figure(figsize=[4.8, 16]) - ax = fig.add_axes([0, 0, 1, 1]) - - for j, n in enumerate(sorted(overlap, reverse=True)): - weight = None - cn = mcd.CSS4_COLORS[n] - xkcd = mcd.XKCD_COLORS["xkcd:" + n].upper() - if cn == xkcd: - weight = 'bold' - - r1 = mpatch.Rectangle((0, j), 1, 1, color=cn) - r2 = mpatch.Rectangle((1, j), 1, 1, color=xkcd) - txt = ax.text(2, j+.5, ' ' + n, va='center', fontsize=10, - weight=weight) - ax.add_patch(r1) - ax.add_patch(r2) - ax.axhline(j, color='k') - - ax.text(.5, j + 1.5, 'X11', ha='center', va='center') - ax.text(1.5, j + 1.5, 'xkcd', ha='center', va='center') - ax.set_xlim(0, 3) - ax.set_ylim(0, j + 2) - ax.axis('off') diff --git a/doc/users/customizing.rst b/doc/users/customizing.rst deleted file mode 100644 index 42b0216fea29..000000000000 --- a/doc/users/customizing.rst +++ /dev/null @@ -1,191 +0,0 @@ -.. _customizing-matplotlib: - -======================== - Customizing matplotlib -======================== - -Using style sheets -================== - -The ``style`` package adds support for easy-to-switch plotting "styles" with -the same parameters as a matplotlibrc_ file (which is read at startup to -configure matplotlib). - -There are a number of pre-defined styles provided by matplotlib. For -example, there's a pre-defined style called "ggplot", which emulates the -aesthetics of ggplot_ (a popular plotting package for R_). To use this style, -just add:: - - >>> import matplotlib.pyplot as plt - >>> plt.style.use('ggplot') - -To list all available styles, use:: - - >>> print(plt.style.available) - - -Defining your own style ------------------------ - -You can create custom styles and use them by calling ``style.use`` with the -path or URL to the style sheet. Additionally, if you add your -``.mplstyle`` file to ``mpl_configdir/stylelib``, you can reuse -your custom style sheet with a call to ``style.use()``. By default -``mpl_configdir`` should be ``~/.config/matplotlib``, but you can check where -yours is with ``matplotlib.get_configdir()``; you may need to create this -directory. You also can change the directory where matplotlib looks for -the stylelib/ folder by setting the MPLCONFIGDIR environment variable, -see :ref:`locating-matplotlib-config-dir`. - -Note that a custom style sheet in ``mpl_configdir/stylelib`` will -override a style sheet defined by matplotlib if the styles have the same name. - -For example, you might want to create -``mpl_configdir/stylelib/presentation.mplstyle`` with the following:: - - axes.titlesize : 24 - axes.labelsize : 20 - lines.linewidth : 3 - lines.markersize : 10 - xtick.labelsize : 16 - ytick.labelsize : 16 - -Then, when you want to adapt a plot designed for a paper to one that looks -good in a presentation, you can just add:: - - >>> import matplotlib.pyplot as plt - >>> plt.style.use('presentation') - - -Composing styles ----------------- - -Style sheets are designed to be composed together. So you can have a style -sheet that customizes colors and a separate style sheet that alters element -sizes for presentations. These styles can easily be combined by passing -a list of styles:: - - >>> import matplotlib.pyplot as plt - >>> plt.style.use(['dark_background', 'presentation']) - -Note that styles further to the right will overwrite values that are already -defined by styles on the left. - - -Temporary styling ------------------ - -If you only want to use a style for a specific block of code but don't want -to change the global styling, the style package provides a context manager -for limiting your changes to a specific scope. To isolate your styling -changes, you can write something like the following:: - - >>> import numpy as np - >>> import matplotlib.pyplot as plt - >>> - >>> with plt.style.context(('dark_background')): - >>> plt.plot(np.sin(np.linspace(0, 2 * np.pi)), 'r-o') - >>> - >>> # Some plotting code with the default style - >>> - >>> plt.show() - - -matplotlib rcParams -=================== - -.. _customizing-with-dynamic-rc-settings: - -Dynamic rc settings -------------------- - -You can also dynamically change the default rc settings in a python script or -interactively from the python shell. All of the rc settings are stored in a -dictionary-like variable called :data:`matplotlib.rcParams`, which is global to -the matplotlib package. rcParams can be modified directly, for example:: - - import matplotlib as mpl - mpl.rcParams['lines.linewidth'] = 2 - mpl.rcParams['lines.color'] = 'r' - -Matplotlib also provides a couple of convenience functions for modifying rc -settings. The :func:`matplotlib.rc` command can be used to modify multiple -settings in a single group at once, using keyword arguments:: - - import matplotlib as mpl - mpl.rc('lines', linewidth=2, color='r') - -The :func:`matplotlib.rcdefaults` command will restore the standard matplotlib -default settings. - -There is some degree of validation when setting the values of rcParams, see -:mod:`matplotlib.rcsetup` for details. - -.. _customizing-with-matplotlibrc-files: - -The :file:`matplotlibrc` file ------------------------------ - -matplotlib uses :file:`matplotlibrc` configuration files to customize all kinds -of properties, which we call `rc settings` or `rc parameters`. You can control -the defaults of almost every property in matplotlib: figure size and dpi, line -width, color and style, axes, axis and grid properties, text and font -properties and so on. matplotlib looks for :file:`matplotlibrc` in four -locations, in the following order: - -1. :file:`matplotlibrc` in the current working directory, usually used for - specific customizations that you do not want to apply elsewhere. - -2. :file:`$MATPLOTLIBRC` if it is a file, else :file:`$MATPLOTLIBRC/matplotlibrc`. - -3. It next looks in a user-specific place, depending on your platform: - - - On Linux and FreeBSD, it looks in :file:`.config/matplotlib/matplotlibrc` - (or `$XDG_CONFIG_HOME/matplotlib/matplotlibrc`) if you've customized - your environment. - - - On other platforms, it looks in :file:`.matplotlib/matplotlibrc`. - - See :ref:`locating-matplotlib-config-dir`. - -4. :file:`{INSTALL}/matplotlib/mpl-data/matplotlibrc`, where - :file:`{INSTALL}` is something like - :file:`/usr/lib/python3.5/site-packages` on Linux, and maybe - :file:`C:\\Python35\\Lib\\site-packages` on Windows. Every time you - install matplotlib, this file will be overwritten, so if you want - your customizations to be saved, please move this file to your - user-specific matplotlib directory. - -Once a :file:`matplotlibrc` file has been found, it will *not* search any of -the other paths. - -To display where the currently active :file:`matplotlibrc` file was -loaded from, one can do the following:: - - >>> import matplotlib - >>> matplotlib.matplotlib_fname() - '/home/foo/.config/matplotlib/matplotlibrc' - -See below for a sample :ref:`matplotlibrc file`. -Although all parameters are optional, you should almost always set the -`backend` or else matplotlib will choose `Agg`, a *non-interactive* backend. -This can lead to unexpected behavior, since if you do not have a -:file:`matplotlibrc` file, it would normally fall back to -:file:`{INSTALL}/matplotlib/mpl-data/matplotlibrc`, which is often set to an -interactive backend by the package maintainer. - -.. _matplotlibrc-sample: - -A sample matplotlibrc file -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. htmlonly:: - - `(download) <../_static/matplotlibrc>`__ - -.. literalinclude:: ../_static/matplotlibrc - - -.. _matplotlibrc: http://matplotlib.org/users/customizing.html -.. _ggplot: http://ggplot2.org/ -.. _R: https://www.r-project.org/ diff --git a/doc/users/dflt_style_changes.rst b/doc/users/dflt_style_changes.rst index ce4182e6d05e..0d6b83517f64 100644 --- a/doc/users/dflt_style_changes.rst +++ b/doc/users/dflt_style_changes.rst @@ -94,7 +94,7 @@ are only specified via hex values. To access these colors outside of the property cycling the notation for colors ``'CN'``, where ``N`` takes values 0-9, was added to denote the first 10 colors in ``mpl.rcParams['axes.prop_cycle']`` See -:ref:`colors` for more details. +:ref:`sphx_glr_tutorials_colors_colors.py` for more details. To restore the old color cycle use @@ -143,7 +143,7 @@ watch Nathaniel Smith and Stéfan van der Walt's talk from SciPy2015. See `here for many more details `__ about the other alternatives and the tools used to create the color map. For details on all of the color maps available in matplotlib see -:ref:`colormaps`. +:ref:`sphx_glr_tutorials_colors_colormaps.py`. .. raw:: html diff --git a/doc/users/examples_index.rst b/doc/users/examples_index.rst index e71c1db6d8a8..7350c2a328f5 100644 --- a/doc/users/examples_index.rst +++ b/doc/users/examples_index.rst @@ -5,4 +5,3 @@ .. toctree:: screenshots.rst - recipes.rst diff --git a/doc/users/gridspec.rst b/doc/users/gridspec.rst deleted file mode 100644 index 2fc48913c692..000000000000 --- a/doc/users/gridspec.rst +++ /dev/null @@ -1,200 +0,0 @@ -.. _gridspec-guide: - - -********************************************** -Customizing Location of Subplot Using GridSpec -********************************************** - - :class:`~matplotlib.gridspec.GridSpec` - specifies the geometry of the grid that a subplot will be - placed. The number of rows and number of columns of the grid - need to be set. Optionally, the subplot layout parameters - (e.g., left, right, etc.) can be tuned. - - :class:`~matplotlib.gridspec.SubplotSpec` - specifies the location of the subplot in the given *GridSpec*. - - :func:`~matplotlib.pyplot.subplot2grid` - a helper function that is similar to :func:`~matplotlib.pyplot.subplot` - but uses 0-based indexing and let subplot to occupy multiple cells. - - -Basic Example of using subplot2grid -=================================== - -To use :func:`~matplotlib.pyplot.subplot2grid`, you provide geometry of -the grid and the location of the subplot in the grid. For a simple -single-cell subplot:: - - ax = plt.subplot2grid((2, 2), (0, 0)) - -is identical to :: - - ax = plt.subplot(2, 2, 1) - -Note that, unlike Matplotlib's subplot, the index starts from 0 in GridSpec. - -To create a subplot that spans multiple cells, :: - - ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2) - ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) - -For example, the following commands :: - - ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3) - ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2) - ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) - ax4 = plt.subplot2grid((3, 3), (2, 0)) - ax5 = plt.subplot2grid((3, 3), (2, 1)) - -creates - -.. figure:: ../gallery/userdemo/images/sphx_glr_demo_gridspec01_000.png - :target: ../gallery/userdemo/demo_gridspec01.html - :align: center - :scale: 50 - - Demo Gridspec01 - - -GridSpec and SubplotSpec -======================== - -You can create :class:`~matplotlib.gridspec.GridSpec` explicitly and use -them to create a subplot. - -For example, :: - - ax = plt.subplot2grid((2, 2), (0, 0)) - -is equal to :: - - import matplotlib.gridspec as gridspec - gs = gridspec.GridSpec(2, 2) - ax = plt.subplot(gs[0, 0]) - -A GridSpec instance provides array-like (2d or 1d) indexing that -returns the SubplotSpec instance. For a SubplotSpec that spans multiple -cells, use slice. :: - - ax2 = plt.subplot(gs[1, :-1]) - ax3 = plt.subplot(gs[1:, -1]) - -The above example becomes :: - - gs = gridspec.GridSpec(3, 3) - ax1 = plt.subplot(gs[0, :]) - ax2 = plt.subplot(gs[1, :-1]) - ax3 = plt.subplot(gs[1:, -1]) - ax4 = plt.subplot(gs[-1, 0]) - ax5 = plt.subplot(gs[-1, -2]) - -.. figure:: ../gallery/userdemo/images/sphx_glr_demo_gridspec02_001.png - :target: ../gallery/userdemo/demo_gridspec02.html - :align: center - :scale: 50 - - Demo Gridspec02 - -Adjust GridSpec layout -====================== - -When a GridSpec is explicitly used, you can adjust the layout -parameters of subplots that are created from the GridSpec. :: - - gs1 = gridspec.GridSpec(3, 3) - gs1.update(left=0.05, right=0.48, wspace=0.05) - -This is similar to :func:`~matplotlib.pyplot.subplots_adjust`, but it only -affects the subplots that are created from the given GridSpec. - -The code below :: - - gs1 = gridspec.GridSpec(3, 3) - gs1.update(left=0.05, right=0.48, wspace=0.05) - ax1 = plt.subplot(gs1[:-1, :]) - ax2 = plt.subplot(gs1[-1, :-1]) - ax3 = plt.subplot(gs1[-1, -1]) - - gs2 = gridspec.GridSpec(3, 3) - gs2.update(left=0.55, right=0.98, hspace=0.05) - ax4 = plt.subplot(gs2[:, :-1]) - ax5 = plt.subplot(gs2[:-1, -1]) - ax6 = plt.subplot(gs2[-1, -1]) - -creates - -.. figure:: ../gallery/userdemo/images/sphx_glr_demo_gridspec03_001.png - :target: ../gallery/userdemo/demo_gridspec03.html - :align: center - :scale: 50 - - Demo Gridspec03 - -GridSpec using SubplotSpec -========================== - -You can create GridSpec from the :class:`~matplotlib.gridspec.SubplotSpec`, -in which case its layout parameters are set to that of the location of -the given SubplotSpec. :: - - gs0 = gridspec.GridSpec(1, 2) - - gs00 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[0]) - gs01 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[1]) - - -.. figure:: ../gallery/userdemo/images/sphx_glr_demo_gridspec04_001.png - :target: ../gallery/userdemo/demo_gridspec04.html - :align: center - :scale: 50 - - Demo Gridspec04 - - -A Complex Nested GridSpec using SubplotSpec -=========================================== - -Here's a more sophisticated example of nested GridSpec where we put -a box around each cell of the outer 4x4 grid, by hiding appropriate -spines in each of the inner 3x3 grids. - -.. figure:: ../gallery/userdemo/images/sphx_glr_demo_gridspec06_001.png - :target: ../gallery/userdemo/demo_gridspec06.html - :align: center - :scale: 50 - - Demo Gridspec06 - - -GridSpec with Varying Cell Sizes -================================ - -By default, GridSpec creates cells of equal sizes. You can adjust -relative heights and widths of rows and columns. Note that absolute -values are meaningless, only their relative ratios matter. :: - - gs = gridspec.GridSpec(2, 2, - width_ratios=[1, 2], - height_ratios=[4, 1] - ) - - ax1 = plt.subplot(gs[0]) - ax2 = plt.subplot(gs[1]) - ax3 = plt.subplot(gs[2]) - ax4 = plt.subplot(gs[3]) - - -.. figure:: ../gallery/userdemo/images/sphx_glr_demo_gridspec05_001.png - :target: ../gallery/userdemo/demo_gridspec05.html - :align: center - :scale: 50 - - Demo Gridspec05 - - - - - - - diff --git a/doc/users/image_tutorial.rst b/doc/users/image_tutorial.rst deleted file mode 100644 index a79fcf2e5ed9..000000000000 --- a/doc/users/image_tutorial.rst +++ /dev/null @@ -1,384 +0,0 @@ -.. _image_tutorial: - - -************** -Image tutorial -************** - -.. _imaging_startup: - -Startup commands -=================== - -First, let's start IPython. It is a most excellent enhancement to the -standard Python prompt, and it ties in especially well with -Matplotlib. Start IPython either at a shell, or the IPython Notebook now. - -With IPython started, we now need to connect to a GUI event loop. This -tells IPython where (and how) to display plots. To connect to a GUI -loop, execute the **%matplotlib** magic at your IPython prompt. There's more -detail on exactly what this does at `IPython's documentation on GUI -event loops -`_. - -If you're using IPython Notebook, the same commands are available, but -people commonly use a specific argument to the %matplotlib magic: - -.. sourcecode:: ipython - - In [1]: %matplotlib inline - -This turns on inline plotting, where plot graphics will appear in your -notebook. This has important implications for interactivity. For inline plotting, commands in -cells below the cell that outputs a plot will not affect the plot. For example, -changing the color map is not possible from cells below the cell that creates a plot. -However, for other backends, such as qt4, that open a separate window, -cells below those that create the plot will change the plot - it is a -live object in memory. - -This tutorial will use matplotlib's imperative-style plotting -interface, pyplot. This interface maintains global state, and is very -useful for quickly and easily experimenting with various plot -settings. The alternative is the object-oriented interface, which is also -very powerful, and generally more suitable for large application -development. If you'd like to learn about the object-oriented -interface, a great place to start is our `FAQ on usage -`_. For now, let's get on -with the imperative-style approach: - -.. sourcecode:: ipython - - In [2]: import matplotlib.pyplot as plt - In [3]: import matplotlib.image as mpimg - In [4]: import numpy as np - -.. _importing_data: - -Importing image data into Numpy arrays -=============================================== - -Loading image data is supported by the `Pillow -`_ library. Natively, matplotlib only -supports PNG images. The commands shown below fall back on Pillow if the -native read fails. - -The image used in this example is a PNG file, but keep that Pillow -requirement in mind for your own data. - -Here's the image we're going to play with: - -.. image:: ../_static/stinkbug.png - -It's a 24-bit RGB PNG image (8 bits for each of R, G, B). Depending -on where you get your data, the other kinds of image that you'll most -likely encounter are RGBA images, which allow for transparency, or -single-channel grayscale (luminosity) images. You can right click on -it and choose "Save image as" to download it to your computer for the -rest of this tutorial. - -And here we go... - -.. sourcecode:: ipython - - In [5]: img=mpimg.imread('stinkbug.png') - Out[5]: - array([[[ 0.40784314, 0.40784314, 0.40784314], - [ 0.40784314, 0.40784314, 0.40784314], - [ 0.40784314, 0.40784314, 0.40784314], - ..., - [ 0.42745098, 0.42745098, 0.42745098], - [ 0.42745098, 0.42745098, 0.42745098], - [ 0.42745098, 0.42745098, 0.42745098]], - - ..., - [[ 0.44313726, 0.44313726, 0.44313726], - [ 0.4509804 , 0.4509804 , 0.4509804 ], - [ 0.4509804 , 0.4509804 , 0.4509804 ], - ..., - [ 0.44705883, 0.44705883, 0.44705883], - [ 0.44705883, 0.44705883, 0.44705883], - [ 0.44313726, 0.44313726, 0.44313726]]], dtype=float32) - -Note the dtype there - float32. Matplotlib has rescaled the 8 bit -data from each channel to floating point data between 0.0 and 1.0. As -a side note, the only datatype that Pillow can work with is uint8. -Matplotlib plotting can handle float32 and uint8, but image -reading/writing for any format other than PNG is limited to uint8 -data. Why 8 bits? Most displays can only render 8 bits per channel -worth of color gradation. Why can they only render 8 bits/channel? -Because that's about all the human eye can see. More here (from a -photography standpoint): `Luminous Landscape bit depth tutorial -`_. - -Each inner list represents a pixel. Here, with an RGB image, there -are 3 values. Since it's a black and white image, R, G, and B are all -similar. An RGBA (where A is alpha, or transparency), has 4 values -per inner list, and a simple luminance image just has one value (and -is thus only a 2-D array, not a 3-D array). For RGB and RGBA images, -matplotlib supports float32 and uint8 data types. For grayscale, -matplotlib supports only float32. If your array data does not meet -one of these descriptions, you need to rescale it. - -.. _plotting_data: - -Plotting numpy arrays as images -=================================== - -So, you have your data in a numpy array (either by importing it, or by -generating it). Let's render it. In Matplotlib, this is performed -using the :func:`~matplotlib.pyplot.imshow` function. Here we'll grab -the plot object. This object gives you an easy way to manipulate the -plot from the prompt. - -.. sourcecode:: ipython - - In [6]: imgplot = plt.imshow(img) - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - imgplot = plt.imshow(img) - -You can also plot any numpy array. - -.. _Pseudocolor: - -Applying pseudocolor schemes to image plots -------------------------------------------------- - -Pseudocolor can be a useful tool for enhancing contrast and -visualizing your data more easily. This is especially useful when -making presentations of your data using projectors - their contrast is -typically quite poor. - -Pseudocolor is only relevant to single-channel, grayscale, luminosity -images. We currently have an RGB image. Since R, G, and B are all -similar (see for yourself above or in your data), we can just pick one -channel of our data: - -.. sourcecode:: ipython - - In [7]: lum_img = img[:,:,0] - -This is array slicing. You can read more in the `Numpy tutorial -`_. - -.. sourcecode:: ipython - - In [8]: plt.imshow(lum_img) - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:, :, 0] - plt.imshow(lum_img) - -Now, with a luminosity (2D, no color) image, the default colormap (aka lookup table, -LUT), is applied. The default is called viridis. There are plenty of -others to choose from. - -.. sourcecode:: ipython - - In [9]: plt.imshow(lum_img, cmap="hot") - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:,:,0] - imgplot = plt.imshow(lum_img) - imgplot.set_cmap('hot') - -Note that you can also change colormaps on existing plot objects using the -:meth:`~matplotlib.image.Image.set_cmap` method: - -.. sourcecode:: ipython - - In [10]: imgplot = plt.imshow(lum_img) - In [11]: imgplot.set_cmap('nipy_spectral') - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:, :, 0] - imgplot = plt.imshow(lum_img) - imgplot.set_cmap('nipy_spectral') - -.. note:: - - However, remember that in the IPython notebook with the inline backend, - you can't make changes to plots that have already been rendered. If you - create imgplot here in one cell, you cannot call set_cmap() on it in a later - cell and expect the earlier plot to change. Make sure that you enter these - commands together in one cell. plt commands will not change plots from earlier - cells. - -There are many other colormap schemes available. See the `list and -images of the colormaps -<../gallery/color/colormaps_reference.html>`_. - -.. _`Color Bars`: - -Color scale reference ------------------------- - -It's helpful to have an idea of what value a color represents. We can -do that by adding color bars. - -.. sourcecode:: ipython - - In [12]: imgplot = plt.imshow(lum_img) - In [13]: plt.colorbar() - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:, :, 0] - imgplot = plt.imshow(lum_img) - imgplot.set_cmap('nipy_spectral') - plt.colorbar() - -This adds a colorbar to your existing figure. This won't -automatically change if you change you switch to a different -colormap - you have to re-create your plot, and add in the colorbar -again. - -.. _`Data ranges`: - -Examining a specific data range ---------------------------------- - -Sometimes you want to enhance the contrast in your image, or expand -the contrast in a particular region while sacrificing the detail in -colors that don't vary much, or don't matter. A good tool to find -interesting regions is the histogram. To create a histogram of our -image data, we use the :func:`~matplotlib.pyplot.hist` function. - -.. sourcecode:: ipython - - In [14]: plt.hist(lum_img.ravel(), bins=256, range=(0.0, 1.0), fc='k', ec='k') - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:,:,0] - plt.hist(lum_img.flatten(), 256, range=(0.0, 1.0), fc='k', ec='k') - -Most often, the "interesting" part of the image is around the peak, -and you can get extra contrast by clipping the regions above and/or -below the peak. In our histogram, it looks like there's not much -useful information in the high end (not many white things in the -image). Let's adjust the upper limit, so that we effectively "zoom in -on" part of the histogram. We do this by passing the clim argument to -imshow. You could also do this by calling the -:meth:`~matplotlib.image.Image.set_clim` method of the image plot -object, but make sure that you do so in the same cell as your plot -command when working with the IPython Notebook - it will not change -plots from earlier cells. - -.. sourcecode:: ipython - - In [15]: imgplot = plt.imshow(lum_img, clim=(0.0, 0.7)) - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - fig = plt.figure() - a=fig.add_subplot(1,2,1) - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:,:,0] - imgplot = plt.imshow(lum_img) - a.set_title('Before') - plt.colorbar(ticks=[0.1,0.3,0.5,0.7], orientation ='horizontal') - a=fig.add_subplot(1,2,2) - imgplot = plt.imshow(lum_img) - imgplot.set_clim(0.0,0.7) - a.set_title('After') - plt.colorbar(ticks=[0.1,0.3,0.5,0.7], orientation='horizontal') - -.. _Interpolation: - -Array Interpolation schemes ---------------------------- - -Interpolation calculates what the color or value of a pixel "should" -be, according to different mathematical schemes. One common place -that this happens is when you resize an image. The number of pixels -change, but you want the same information. Since pixels are discrete, -there's missing space. Interpolation is how you fill that space. -This is why your images sometimes come out looking pixelated when you -blow them up. The effect is more pronounced when the difference -between the original image and the expanded image is greater. Let's -take our image and shrink it. We're effectively discarding pixels, -only keeping a select few. Now when we plot it, that data gets blown -up to the size on your screen. The old pixels aren't there anymore, -and the computer has to draw in pixels to fill that space. - -We'll use the Pillow library that we used to load the image also to resize -the image. - -.. sourcecode:: ipython - - In [16]: from PIL import Image - In [17]: img = Image.open('../_static/stinkbug.png') - In [18]: img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place - In [19]: imgplot = plt.imshow(img) - -.. plot:: - - import matplotlib.pyplot as plt - from PIL import Image - img = Image.open('../_static/stinkbug.png') # opens the file using Pillow - it's not an array yet - img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place - imgplot = plt.imshow(img) - -Here we have the default interpolation, bilinear, since we did not -give :func:`~matplotlib.pyplot.imshow` any interpolation argument. - -Let's try some others: - -.. sourcecode:: ipython - - In [20]: imgplot = plt.imshow(img, interpolation="nearest") - -.. plot:: - - import matplotlib.pyplot as plt - from PIL import Image - img = Image.open('../_static/stinkbug.png') # opens the file using Pillow - it's not an array yet - img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place - imgplot = plt.imshow(img, interpolation="nearest") - -.. sourcecode:: ipython - - In [21]: imgplot = plt.imshow(img, interpolation="bicubic") - -.. plot:: - - import matplotlib.pyplot as plt - from PIL import Image - img = Image.open('../_static/stinkbug.png') # opens the file using Pillow - it's not an array yet - img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place - imgplot = plt.imshow(img, interpolation="bicubic") - -Bicubic interpolation is often used when blowing up photos - people -tend to prefer blurry over pixelated. diff --git a/doc/users/index.rst b/doc/users/index.rst index 566205ba8a3a..ec79d23a953e 100644 --- a/doc/users/index.rst +++ b/doc/users/index.rst @@ -14,10 +14,6 @@ User's Guide intro.rst installing.rst - tutorials.rst - index_text.rst - color_index.rst - customizing.rst interactive.rst examples_index whats_new.rst diff --git a/doc/users/index_text.rst b/doc/users/index_text.rst deleted file mode 100644 index 7904d7e3173e..000000000000 --- a/doc/users/index_text.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _text-guide: - -Working with text -################# - -.. toctree:: - - text_intro.rst - text_props.rst - annotations.rst - mathtext.rst - usetex.rst - pgf.rst diff --git a/doc/users/intro.rst b/doc/users/intro.rst index 99ea455a72e7..76b5c3bf1ecf 100644 --- a/doc/users/intro.rst +++ b/doc/users/intro.rst @@ -62,10 +62,10 @@ The Matplotlib code is conceptually divided into three parts: the *pylab interface* is the set of functions provided by :mod:`matplotlib.pylab` which allow the user to create plots with code quite similar to MATLAB figure generating code -(:ref:`pyplot-tutorial`). The *Matplotlib frontend* or *Matplotlib +(:ref:`sphx_glr_tutorials_01_introductory_pyplot.py`). The *Matplotlib frontend* or *Matplotlib API* is the set of classes that do the heavy lifting, creating and managing figures, text, lines, plots and so on -(:ref:`artist-tutorial`). This is an abstract interface that knows +(:ref:`sphx_glr_tutorials_02_intermediate_artists.py`). This is an abstract interface that knows nothing about output. The *backends* are device-dependent drawing devices, aka renderers, that transform the frontend representation to hardcopy or a display device (:ref:`what-is-a-backend`). Example diff --git a/doc/users/legend_guide.rst b/doc/users/legend_guide.rst deleted file mode 100644 index 8f179f34f8d2..000000000000 --- a/doc/users/legend_guide.rst +++ /dev/null @@ -1,306 +0,0 @@ -.. _plotting-guide-legend: - -************ -Legend guide -************ - -.. currentmodule:: matplotlib.pyplot - - -This legend guide is an extension of the documentation available at -:func:`~matplotlib.pyplot.legend` - please ensure you are familiar with -contents of that documentation before proceeding with this guide. - - -This guide makes use of some common terms, which are documented here for clarity: - -.. glossary:: - - legend entry - A legend is made up of one or more legend entries. An entry is made up of - exactly one key and one label. - - legend key - The colored/patterned marker to the left of each legend label. - - legend label - The text which describes the handle represented by the key. - - legend handle - The original object which is used to generate an appropriate entry in - the legend. - - -Controlling the legend entries -============================== - -Calling :func:`legend` with no arguments automatically fetches the legend -handles and their associated labels. This functionality is equivalent to:: - - handles, labels = ax.get_legend_handles_labels() - ax.legend(handles, labels) - -The :meth:`~matplotlib.axes.Axes.get_legend_handles_labels` function returns -a list of handles/artists which exist on the Axes which can be used to -generate entries for the resulting legend - it is worth noting however that -not all artists can be added to a legend, at which point a "proxy" will have -to be created (see :ref:`proxy_legend_handles` for further details). - -For full control of what is being added to the legend, it is common to pass -the appropriate handles directly to :func:`legend`:: - - line_up, = plt.plot([1,2,3], label='Line 2') - line_down, = plt.plot([3,2,1], label='Line 1') - plt.legend(handles=[line_up, line_down]) - -In some cases, it is not possible to set the label of the handle, so it is -possible to pass through the list of labels to :func:`legend`:: - - line_up, = plt.plot([1,2,3], label='Line 2') - line_down, = plt.plot([3,2,1], label='Line 1') - plt.legend([line_up, line_down], ['Line Up', 'Line Down']) - - -.. _proxy_legend_handles: - -Creating artists specifically for adding to the legend (aka. Proxy artists) -=========================================================================== - -Not all handles can be turned into legend entries automatically, -so it is often necessary to create an artist which *can*. Legend handles -don't have to exists on the Figure or Axes in order to be used. - -Suppose we wanted to create a legend which has an entry for some data which -is represented by a red color: - -.. plot:: - :include-source: - - import matplotlib.patches as mpatches - import matplotlib.pyplot as plt - - red_patch = mpatches.Patch(color='red', label='The red data') - plt.legend(handles=[red_patch]) - - plt.show() - -There are many supported legend handles, instead of creating a patch of color -we could have created a line with a marker: - -.. plot:: - :include-source: - - import matplotlib.lines as mlines - import matplotlib.pyplot as plt - - blue_line = mlines.Line2D([], [], color='blue', marker='*', - markersize=15, label='Blue stars') - plt.legend(handles=[blue_line]) - - plt.show() - - -Legend location -=============== - -The location of the legend can be specified by the keyword argument -*loc*. Please see the documentation at :func:`legend` for more details. - -The ``bbox_to_anchor`` keyword gives a great degree of control for manual -legend placement. For example, if you want your axes legend located at the -figure's top right-hand corner instead of the axes' corner, simply specify -the corner's location, and the coordinate system of that location:: - - plt.legend(bbox_to_anchor=(1, 1), - bbox_transform=plt.gcf().transFigure) - -More examples of custom legend placement: - -.. figure:: ../gallery/userdemo/images/sphx_glr_simple_legend01_001.png - :target: ../gallery/userdemo/simple_legend01.html - :align: center - :scale: 50 - - Simple Legend01 - - -Multiple legends on the same Axes -================================= - -Sometimes it is more clear to split legend entries across multiple -legends. Whilst the instinctive approach to doing this might be to call -the :func:`legend` function multiple times, you will find that only one -legend ever exists on the Axes. This has been done so that it is possible -to call :func:`legend` repeatedly to update the legend to the latest -handles on the Axes, so to persist old legend instances, we must add them -manually to the Axes: - -.. figure:: ../gallery/userdemo/images/sphx_glr_simple_legend02_001.png - :target: ../gallery/userdemo/simple_legend02.html - :align: center - :scale: 50 - - Simple Legend02 - -Legend Handlers -=============== - -In order to create legend entries, handles are given as an argument to an -appropriate :class:`~matplotlib.legend_handler.HandlerBase` subclass. -The choice of handler subclass is determined by the following rules: - - 1. Update :func:`~matplotlib.legend.Legend.get_legend_handler_map` - with the value in the ``handler_map`` keyword. - 2. Check if the ``handle`` is in the newly created ``handler_map``. - 3. Check if the type of ``handle`` is in the newly created - ``handler_map``. - 4. Check if any of the types in the ``handle``'s mro is in the newly - created ``handler_map``. - -For completeness, this logic is mostly implemented in -:func:`~matplotlib.legend.Legend.get_legend_handler`. - -All of this flexibility means that we have the necessary hooks to implement -custom handlers for our own type of legend key. - -The simplest example of using custom handlers is to instantiate one of the -existing :class:`~matplotlib.legend_handler.HandlerBase` subclasses. For the -sake of simplicity, let's choose :class:`matplotlib.legend_handler.HandlerLine2D` -which accepts a ``numpoints`` argument (note numpoints is a keyword -on the :func:`legend` function for convenience). We can then pass the mapping -of instance to Handler as a keyword to legend. - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - from matplotlib.legend_handler import HandlerLine2D - - line1, = plt.plot([3,2,1], marker='o', label='Line 1') - line2, = plt.plot([1,2,3], marker='o', label='Line 2') - - plt.legend(handler_map={line1: HandlerLine2D(numpoints=4)}) - -As you can see, "Line 1" now has 4 marker points, where "Line 2" has 2 (the -default). Try the above code, only change the map's key from ``line1`` to -``type(line1)``. Notice how now both :class:`~matplotlib.lines.Line2D` instances -get 4 markers. - -Along with handlers for complex plot types such as errorbars, stem plots -and histograms, the default ``handler_map`` has a special ``tuple`` handler -(:class:`~matplotlib.legend_handler.HandlerTuple`) which simply plots -the handles on top of one another for each item in the given tuple. The -following example demonstrates combining two legend keys on top of one another: - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - from numpy.random import randn - - z = randn(10) - - red_dot, = plt.plot(z, "ro", markersize=15) - # Put a white cross over some of the data. - white_cross, = plt.plot(z[:5], "w+", markeredgewidth=3, markersize=15) - - plt.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"]) - -The :class:`~matplotlib.legend_handler.HandlerTuple` class can also be used to -assign several legend keys to the same entry: - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - from matplotlib.legend_handler import HandlerLine2D, HandlerTuple - - p1, = plt.plot([1, 2.5, 3], 'r-d') - p2, = plt.plot([3, 2, 1], 'k-o') - - l = plt.legend([(p1, p2)], ['Two keys'], numpoints=1, - handler_map={tuple: HandlerTuple(ndivide=None)}) - - -Implementing a custom legend handler ------------------------------------- - -A custom handler can be implemented to turn any handle into a legend key (handles -don't necessarily need to be matplotlib artists). -The handler must implement a "legend_artist" method which returns a -single artist for the legend to use. Signature details about the "legend_artist" -are documented at :meth:`~matplotlib.legend_handler.HandlerBase.legend_artist`. - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import matplotlib.patches as mpatches - - class AnyObject(object): - pass - - class AnyObjectHandler(object): - def legend_artist(self, legend, orig_handle, fontsize, handlebox): - x0, y0 = handlebox.xdescent, handlebox.ydescent - width, height = handlebox.width, handlebox.height - patch = mpatches.Rectangle([x0, y0], width, height, facecolor='red', - edgecolor='black', hatch='xx', lw=3, - transform=handlebox.get_transform()) - handlebox.add_artist(patch) - return patch - - plt.legend([AnyObject()], ['My first handler'], - handler_map={AnyObject: AnyObjectHandler()}) - -Alternatively, had we wanted to globally accept ``AnyObject`` instances without -needing to manually set the ``handler_map`` keyword all the time, we could have -registered the new handler with:: - - from matplotlib.legend import Legend - Legend.update_default_handler_map({AnyObject: AnyObjectHandler()}) - -Whilst the power here is clear, remember that there are already many handlers -implemented and what you want to achieve may already be easily possible with -existing classes. For example, to produce elliptical legend keys, rather than -rectangular ones: - -.. plot:: - :include-source: - - from matplotlib.legend_handler import HandlerPatch - import matplotlib.pyplot as plt - import matplotlib.patches as mpatches - - - class HandlerEllipse(HandlerPatch): - def create_artists(self, legend, orig_handle, - xdescent, ydescent, width, height, fontsize, trans): - center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent - p = mpatches.Ellipse(xy=center, width=width + xdescent, - height=height + ydescent) - self.update_prop(p, orig_handle, legend) - p.set_transform(trans) - return [p] - - - c = mpatches.Circle((0.5, 0.5), 0.25, facecolor="green", - edgecolor="red", linewidth=3) - plt.gca().add_patch(c) - - plt.legend([c], ["An ellipse, not a rectangle"], - handler_map={mpatches.Circle: HandlerEllipse()}) - -Known examples of using legend -============================== - -Here is a non-exhaustive list of the examples available involving legend -being used in various ways: - -* :ref:`api-legend` -* :ref:`lines_bars_and_markers-scatter_with_legend` -* :ref:`pylab_examples-contourf_hatching` -* :ref:`pylab_examples-figlegend_demo` -* :ref:`pylab_examples-scatter_symbol` - - diff --git a/doc/users/mathtext.rst b/doc/users/mathtext.rst deleted file mode 100644 index 6904f9b2a5f3..000000000000 --- a/doc/users/mathtext.rst +++ /dev/null @@ -1,350 +0,0 @@ -.. _mathtext-tutorial: - -Writing mathematical expressions -================================ - -You can use a subset TeX markup in any matplotlib text string by -placing it inside a pair of dollar signs ($). - -Note that you do not need to have TeX installed, since matplotlib -ships its own TeX expression parser, layout engine and fonts. The -layout engine is a fairly direct adaptation of the layout algorithms -in Donald Knuth's TeX, so the quality is quite good (matplotlib also -provides a ``usetex`` option for those who do want to call out to TeX -to generate their text (see :ref:`usetex-tutorial`). - -Any text element can use math text. You should use raw strings (precede the -quotes with an ``'r'``), and surround the math text with dollar signs ($), as in -TeX. Regular text and mathtext can be interleaved within the same string. -Mathtext can use DejaVu Sans (default), DejaVu Serif, the Computer Modern fonts -(from (La)TeX), `STIX `_ fonts (with are designed -to blend well with Times), or a Unicode font that you provide. The mathtext -font can be selected with the customization variable ``mathtext.fontset`` (see -:ref:`customizing-matplotlib`) - -.. note:: - On `"narrow" `_ builds - of Python, if you use the STIX fonts you should also set - ``ps.fonttype`` and ``pdf.fonttype`` to 3 (the default), not 42. - Otherwise `some characters will not be visible - `_. - -Here is a simple example:: - - # plain text - plt.title('alpha > beta') - -produces "alpha > beta". - -Whereas this:: - - # math text - plt.title(r'$\alpha > \beta$') - -produces ":math:`\alpha > \beta`". - -.. note:: - Mathtext should be placed between a pair of dollar signs ($). To - make it easy to display monetary values, e.g., "$100.00", if a - single dollar sign is present in the entire string, it will be - displayed verbatim as a dollar sign. This is a small change from - regular TeX, where the dollar sign in non-math text would have to - be escaped ('\\\$'). - -.. note:: - While the syntax inside the pair of dollar signs ($) aims to be - TeX-like, the text outside does not. In particular, characters - such as:: - - # $ % & ~ _ ^ \ { } \( \) \[ \] - - have special meaning outside of math mode in TeX. Therefore, these - characters will behave differently depending on the rcParam - ``text.usetex`` flag. See the :ref:`usetex tutorial - ` for more information. - -Subscripts and superscripts ---------------------------- - -To make subscripts and superscripts, use the ``'_'`` and ``'^'`` symbols:: - - r'$\alpha_i > \beta_i$' - -.. math:: - - \alpha_i > \beta_i - -Some symbols automatically put their sub/superscripts under and over -the operator. For example, to write the sum of :math:`x_i` from :math:`0` to -:math:`\infty`, you could do:: - - r'$\sum_{i=0}^\infty x_i$' - -.. math:: - - \sum_{i=0}^\infty x_i - -Fractions, binomials and stacked numbers ----------------------------------------- - -Fractions, binomials and stacked numbers can be created with the -``\frac{}{}``, ``\binom{}{}`` and ``\stackrel{}{}`` commands, -respectively:: - - r'$\frac{3}{4} \binom{3}{4} \stackrel{3}{4}$' - -produces - -.. math:: - - \frac{3}{4} \binom{3}{4} \stackrel{3}{4} - -Fractions can be arbitrarily nested:: - - r'$\frac{5 - \frac{1}{x}}{4}$' - -produces - -.. math:: - - \frac{5 - \frac{1}{x}}{4} - -Note that special care needs to be taken to place parentheses and brackets around -fractions. Doing things the obvious way produces brackets that are -too small:: - - r'$(\frac{5 - \frac{1}{x}}{4})$' - -.. math :: - - (\frac{5 - \frac{1}{x}}{4}) - -The solution is to precede the bracket with ``\left`` and ``\right`` -to inform the parser that those brackets encompass the entire object:: - - r'$\left(\frac{5 - \frac{1}{x}}{4}\right)$' - -.. math :: - - \left(\frac{5 - \frac{1}{x}}{4}\right) - -Radicals --------- - -Radicals can be produced with the ``\sqrt[]{}`` command. For example:: - - r'$\sqrt{2}$' - -.. math :: - - \sqrt{2} - -Any base can (optionally) be provided inside square brackets. Note -that the base must be a simple expression, and can not contain layout -commands such as fractions or sub/superscripts:: - - r'$\sqrt[3]{x}$' - -.. math :: - - \sqrt[3]{x} - -Fonts ------ - -The default font is *italics* for mathematical symbols. - -.. note:: - - This default can be changed using the ``mathtext.default`` rcParam. - This is useful, for example, to use the same font as regular - non-math text for math text, by setting it to ``regular``. - -To change fonts, e.g., to write "sin" in a Roman font, enclose the text -in a font command:: - - r'$s(t) = \mathcal{A}\mathrm{sin}(2 \omega t)$' - -.. math:: - - s(t) = \mathcal{A}\mathrm{sin}(2 \omega t) - -More conveniently, many commonly used function names that are typeset in a -Roman font have shortcuts. So the expression above could be written -as follows:: - - r'$s(t) = \mathcal{A}\sin(2 \omega t)$' - -.. math:: - - s(t) = \mathcal{A}\sin(2 \omega t) - -Here "s" and "t" are variable in italics font (default), "sin" is in -Roman font, and the amplitude "A" is in calligraphy font. Note in the -example above the caligraphy ``A`` is squished into the ``sin``. You -can use a spacing command to add a little whitespace between them:: - - s(t) = \mathcal{A}\/\sin(2 \omega t) - -.. math:: - - s(t) = \mathcal{A}\/\sin(2 \omega t) - -The choices available with all fonts are: - - ============================ ================================== - Command Result - ============================ ================================== - ``\mathrm{Roman}`` :math:`\mathrm{Roman}` - ``\mathit{Italic}`` :math:`\mathit{Italic}` - ``\mathtt{Typewriter}`` :math:`\mathtt{Typewriter}` - ``\mathcal{CALLIGRAPHY}`` :math:`\mathcal{CALLIGRAPHY}` - ============================ ================================== - -.. role:: math-stix(math) - :fontset: stix - -When using the `STIX `_ fonts, you also have the choice of: - - ====================================== ========================================= - Command Result - ====================================== ========================================= - ``\mathbb{blackboard}`` :math-stix:`\mathbb{blackboard}` - ``\mathrm{\mathbb{blackboard}}`` :math-stix:`\mathrm{\mathbb{blackboard}}` - ``\mathfrak{Fraktur}`` :math-stix:`\mathfrak{Fraktur}` - ``\mathsf{sansserif}`` :math-stix:`\mathsf{sansserif}` - ``\mathrm{\mathsf{sansserif}}`` :math-stix:`\mathrm{\mathsf{sansserif}}` - ====================================== ========================================= - - .. htmlonly:: - - ====================================== ========================================= - ``\mathcircled{circled}`` :math-stix:`\mathcircled{circled}` - ====================================== ========================================= - -There are also three global "font sets" to choose from, which are -selected using the ``mathtext.fontset`` parameter in -:ref:`matplotlibrc `. - -``cm``: **Computer Modern (TeX)** - -.. image:: ../_static/cm_fontset.png - -``stix``: **STIX** (designed to blend well with Times) - -.. image:: ../_static/stix_fontset.png - -``stixsans``: **STIX sans-serif** - -.. image:: ../_static/stixsans_fontset.png - -Additionally, you can use ``\mathdefault{...}`` or its alias -``\mathregular{...}`` to use the font used for regular text outside of -mathtext. There are a number of limitations to this approach, most -notably that far fewer symbols will be available, but it can be useful -to make math expressions blend well with other text in the plot. - -Custom fonts -~~~~~~~~~~~~ - -mathtext also provides a way to use custom fonts for math. This -method is fairly tricky to use, and should be considered an -experimental feature for patient users only. By setting the rcParam -``mathtext.fontset`` to ``custom``, you can then set the following -parameters, which control which font file to use for a particular set -of math characters. - - ============================== ================================= - Parameter Corresponds to - ============================== ================================= - ``mathtext.it`` ``\mathit{}`` or default italic - ``mathtext.rm`` ``\mathrm{}`` Roman (upright) - ``mathtext.tt`` ``\mathtt{}`` Typewriter (monospace) - ``mathtext.bf`` ``\mathbf{}`` bold italic - ``mathtext.cal`` ``\mathcal{}`` calligraphic - ``mathtext.sf`` ``\mathsf{}`` sans-serif - ============================== ================================= - -Each parameter should be set to a fontconfig font descriptor (as -defined in the yet-to-be-written font chapter). - -.. TODO: Link to font chapter - -The fonts used should have a Unicode mapping in order to find any -non-Latin characters, such as Greek. If you want to use a math symbol -that is not contained in your custom fonts, you can set the rcParam -``mathtext.fallback_to_cm`` to ``True`` which will cause the mathtext -system to use characters from the default Computer Modern fonts -whenever a particular character can not be found in the custom font. - -Note that the math glyphs specified in Unicode have evolved over time, -and many fonts may not have glyphs in the correct place for mathtext. - -Accents -------- - -An accent command may precede any symbol to add an accent above it. -There are long and short forms for some of them. - - ============================== ================================= - Command Result - ============================== ================================= - ``\acute a`` or ``\'a`` :math:`\acute a` - ``\bar a`` :math:`\bar a` - ``\breve a`` :math:`\breve a` - ``\ddot a`` or ``\"a`` :math:`\ddot a` - ``\dot a`` or ``\.a`` :math:`\dot a` - ``\grave a`` or ``\`a`` :math:`\grave a` - ``\hat a`` or ``\^a`` :math:`\hat a` - ``\tilde a`` or ``\~a`` :math:`\tilde a` - ``\vec a`` :math:`\vec a` - ``\overline{abc}`` :math:`\overline{abc}` - ============================== ================================= - -In addition, there are two special accents that automatically adjust -to the width of the symbols below: - - ============================== ================================= - Command Result - ============================== ================================= - ``\widehat{xyz}`` :math:`\widehat{xyz}` - ``\widetilde{xyz}`` :math:`\widetilde{xyz}` - ============================== ================================= - -Care should be taken when putting accents on lower-case i's and j's. -Note that in the following ``\imath`` is used to avoid the extra dot -over the i:: - - r"$\hat i\ \ \hat \imath$" - -.. math:: - - \hat i\ \ \hat \imath - -Symbols -------- - -You can also use a large number of the TeX symbols, as in ``\infty``, -``\leftarrow``, ``\sum``, ``\int``. - -.. math_symbol_table:: - -If a particular symbol does not have a name (as is true of many of the -more obscure symbols in the STIX fonts), Unicode characters can -also be used:: - - ur'$\u23ce$' - -Example -------- - -Here is an example illustrating many of these features in context. - -.. figure:: ../gallery/pyplots/images/sphx_glr_pyplot_mathtext_001.png - :target: ../gallery/pyplots/pyplot_mathtext.html - :align: center - :scale: 50 - - Pyplot Mathtext - - diff --git a/doc/users/path_tutorial.rst b/doc/users/path_tutorial.rst deleted file mode 100644 index f820a1eeb4dc..000000000000 --- a/doc/users/path_tutorial.rst +++ /dev/null @@ -1,194 +0,0 @@ -.. _path_tutorial: - -************* -Path Tutorial -************* - -The object underlying all of the :mod:`matplotlib.patch` objects is -the :class:`~matplotlib.path.Path`, which supports the standard set of -moveto, lineto, curveto commands to draw simple and compound outlines -consisting of line segments and splines. The ``Path`` is instantiated -with a (N,2) array of (x,y) vertices, and a N-length array of path -codes. For example to draw the unit rectangle from (0,0) to (1,1), we -could use this code - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - from matplotlib.path import Path - import matplotlib.patches as patches - - verts = [ - (0., 0.), # left, bottom - (0., 1.), # left, top - (1., 1.), # right, top - (1., 0.), # right, bottom - (0., 0.), # ignored - ] - - codes = [Path.MOVETO, - Path.LINETO, - Path.LINETO, - Path.LINETO, - Path.CLOSEPOLY, - ] - - path = Path(verts, codes) - - fig = plt.figure() - ax = fig.add_subplot(111) - patch = patches.PathPatch(path, facecolor='orange', lw=2) - ax.add_patch(patch) - ax.set_xlim(-2,2) - ax.set_ylim(-2,2) - plt.show() - - -The following path codes are recognized - -============== ================================= ==================================================================================================================== -Code Vertices Description -============== ================================= ==================================================================================================================== -``STOP`` 1 (ignored) A marker for the end of the entire path (currently not required and ignored) -``MOVETO`` 1 Pick up the pen and move to the given vertex. -``LINETO`` 1 Draw a line from the current position to the given vertex. -``CURVE3`` 2 (1 control point, 1 endpoint) Draw a quadratic Bézier curve from the current position, with the given control point, to the given end point. -``CURVE4`` 3 (2 control points, 1 endpoint) Draw a cubic Bézier curve from the current position, with the given control points, to the given end point. -``CLOSEPOLY`` 1 (point itself is ignored) Draw a line segment to the start point of the current polyline. -============== ================================= ==================================================================================================================== - - -.. path-curves: - - -Bézier example -============== - -Some of the path components require multiple vertices to specify them: -for example CURVE 3 is a `bézier -`_ curve with one -control point and one end point, and CURVE4 has three vertices for the -two control points and the end point. The example below shows a -CURVE4 Bézier spline -- the bézier curve will be contained in the -convex hull of the start point, the two control points, and the end -point - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - from matplotlib.path import Path - import matplotlib.patches as patches - - verts = [ - (0., 0.), # P0 - (0.2, 1.), # P1 - (1., 0.8), # P2 - (0.8, 0.), # P3 - ] - - codes = [Path.MOVETO, - Path.CURVE4, - Path.CURVE4, - Path.CURVE4, - ] - - path = Path(verts, codes) - - fig = plt.figure() - ax = fig.add_subplot(111) - patch = patches.PathPatch(path, facecolor='none', lw=2) - ax.add_patch(patch) - - xs, ys = zip(*verts) - ax.plot(xs, ys, 'x--', lw=2, color='black', ms=10) - - ax.text(-0.05, -0.05, 'P0') - ax.text(0.15, 1.05, 'P1') - ax.text(1.05, 0.85, 'P2') - ax.text(0.85, -0.05, 'P3') - - ax.set_xlim(-0.1, 1.1) - ax.set_ylim(-0.1, 1.1) - plt.show() - -.. compound_paths: - -Compound paths -============== - -All of the simple patch primitives in matplotlib, Rectangle, Circle, -Polygon, etc, are implemented with simple path. Plotting functions -like :meth:`~matplotlib.axes.Axes.hist` and -:meth:`~matplotlib.axes.Axes.bar`, which create a number of -primitives, e.g., a bunch of Rectangles, can usually be implemented more -efficiently using a compound path. The reason ``bar`` creates a list -of rectangles and not a compound path is largely historical: the -:class:`~matplotlib.path.Path` code is comparatively new and ``bar`` -predates it. While we could change it now, it would break old code, -so here we will cover how to create compound paths, replacing the -functionality in bar, in case you need to do so in your own code for -efficiency reasons, e.g., you are creating an animated bar plot. - -We will make the histogram chart by creating a series of rectangles -for each histogram bar: the rectangle width is the bin width and the -rectangle height is the number of datapoints in that bin. First we'll -create some random normally distributed data and compute the -histogram. Because numpy returns the bin edges and not centers, the -length of ``bins`` is 1 greater than the length of ``n`` in the -example below:: - - # histogram our data with numpy - data = np.random.randn(1000) - n, bins = np.histogram(data, 100) - -We'll now extract the corners of the rectangles. Each of the -``left``, ``bottom``, etc, arrays below is ``len(n)``, where ``n`` is -the array of counts for each histogram bar:: - - # get the corners of the rectangles for the histogram - left = np.array(bins[:-1]) - right = np.array(bins[1:]) - bottom = np.zeros(len(left)) - top = bottom + n - -Now we have to construct our compound path, which will consist of a -series of ``MOVETO``, ``LINETO`` and ``CLOSEPOLY`` for each rectangle. -For each rectangle, we need 5 vertices: 1 for the ``MOVETO``, 3 for -the ``LINETO``, and 1 for the ``CLOSEPOLY``. As indicated in the -table above, the vertex for the closepoly is ignored but we still need -it to keep the codes aligned with the vertices:: - - nverts = nrects*(1+3+1) - verts = np.zeros((nverts, 2)) - codes = np.ones(nverts, int) * path.Path.LINETO - codes[0::5] = path.Path.MOVETO - codes[4::5] = path.Path.CLOSEPOLY - verts[0::5,0] = left - verts[0::5,1] = bottom - verts[1::5,0] = left - verts[1::5,1] = top - verts[2::5,0] = right - verts[2::5,1] = top - verts[3::5,0] = right - verts[3::5,1] = bottom - -All that remains is to create the path, attach it to a -:class:`~matplotlib.patch.PathPatch`, and add it to our axes:: - - barpath = path.Path(verts, codes) - patch = patches.PathPatch(barpath, facecolor='green', - edgecolor='yellow', alpha=0.5) - ax.add_patch(patch) - -Here is the result - -.. figure:: ../gallery/pyplots/images/sphx_glr_compound_path_demo_001.png - :target: ../gallery/pyplots/compound_path_demo.html - :align: center - :scale: 50 - - Compound Path Demo - - diff --git a/doc/users/patheffects_guide.rst b/doc/users/patheffects_guide.rst deleted file mode 100644 index e674f4be4bac..000000000000 --- a/doc/users/patheffects_guide.rst +++ /dev/null @@ -1,134 +0,0 @@ -.. _patheffects-guide: - -****************** -Path effects guide -****************** - -.. py:module:: matplotlib.patheffects - - -Matplotlib's :mod:`~matplotlib.patheffects` module provides functionality to -apply a multiple draw stage to any Artist which can be rendered via a -:class:`~matplotlib.path.Path`. - -Artists which can have a path effect applied to them include :class:`~matplotlib.patches.Patch`, -:class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.collections.Collection` and even -:class:`~matplotlib.text.Text`. Each artist's path effects can be controlled via the -``set_path_effects`` method (:class:`~matplotlib.artist.Artist.set_path_effects`), which takes -an iterable of :class:`AbstractPathEffect` instances. - -The simplest path effect is the :class:`Normal` effect, which simply -draws the artist without any effect: - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import matplotlib.patheffects as path_effects - - fig = plt.figure(figsize=(5, 1.5)) - text = fig.text(0.5, 0.5, 'Hello path effects world!\nThis is the normal ' - 'path effect.\nPretty dull, huh?', - ha='center', va='center', size=20) - text.set_path_effects([path_effects.Normal()]) - plt.show() - -Whilst the plot doesn't look any different to what you would expect without any path -effects, the drawing of the text now been changed to use the path effects -framework, opening up the possibilities for more interesting examples. - -Adding a shadow ---------------- - -A far more interesting path effect than :class:`Normal` is the -drop-shadow, which we can apply to any of our path based artists. The classes -:class:`SimplePatchShadow` and -:class:`SimpleLineShadow` do precisely this by drawing either a filled -patch or a line patch below the original artist: - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import matplotlib.patheffects as path_effects - - text = plt.text(0.5, 0.5, 'Hello path effects world!', - path_effects=[path_effects.withSimplePatchShadow()]) - - plt.plot([0, 3, 2, 5], linewidth=5, color='blue', - path_effects=[path_effects.SimpleLineShadow(), - path_effects.Normal()]) - plt.show() - - -Notice the two approaches to setting the path effects in this example. The -first uses the ``with*`` classes to include the desired functionality automatically -followed with the "normal" effect, whereas the latter explicitly defines the two path -effects to draw. - -Making an artist stand out --------------------------- - -One nice way of making artists visually stand out is to draw an outline in a bold -color below the actual artist. The :class:`Stroke` path effect -makes this a relatively simple task: - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import matplotlib.patheffects as path_effects - - fig = plt.figure(figsize=(7, 1)) - text = fig.text(0.5, 0.5, 'This text stands out because of\n' - 'its black border.', color='white', - ha='center', va='center', size=30) - text.set_path_effects([path_effects.Stroke(linewidth=3, foreground='black'), - path_effects.Normal()]) - plt.show() - -It is important to note that this effect only works because we have drawn the text -path twice; once with a thick black line, and then once with the original text -path on top. - -You may have noticed that the keywords to :class:`Stroke` and -:class:`SimplePatchShadow` and :class:`SimpleLineShadow` are not the usual Artist -keywords (such as ``facecolor`` and ``edgecolor`` etc.). This is because with these -path effects we are operating at lower level of matplotlib. In fact, the keywords -which are accepted are those for a :class:`matplotlib.backend_bases.GraphicsContextBase` -instance, which have been designed for making it easy to create new backends - and not -for its user interface. - - -Greater control of the path effect artist ------------------------------------------ - -As already mentioned, some of the path effects operate at a lower level than most users -will be used to, meaning that setting keywords such as ``facecolor`` and ``edgecolor`` -raise an AttributeError. Luckily there is a generic :class:`PathPatchEffect` path effect -which creates a :class:`~matplotlib.patches.PathPatch` class with the original path. -The keywords to this effect are identical to those of :class:`~matplotlib.patches.PathPatch`: - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import matplotlib.patheffects as path_effects - - fig = plt.figure(figsize=(8, 1)) - t = fig.text(0.02, 0.5, 'Hatch shadow', fontsize=75, weight=1000, va='center') - t.set_path_effects([path_effects.PathPatchEffect(offset=(4, -4), hatch='xxxx', - facecolor='gray'), - path_effects.PathPatchEffect(edgecolor='white', linewidth=1.1, - facecolor='black')]) - plt.show() - - -.. - Headings for future consideration: - - Implementing a custom path effect - --------------------------------- - - What is going on under the hood - -------------------------------- diff --git a/doc/users/prev_whats_new/whats_new_0.98.4.rst b/doc/users/prev_whats_new/whats_new_0.98.4.rst index 07665d9a8a5f..3cb48c72e4ed 100644 --- a/doc/users/prev_whats_new/whats_new_0.98.4.rst +++ b/doc/users/prev_whats_new/whats_new_0.98.4.rst @@ -79,7 +79,7 @@ psd amplitude scaling Ryan May did a lot of work to rationalize the amplitude scaling of :func:`~matplotlib.pyplot.psd` and friends. See -:ref:`pylab_examples-psd_demo2`. and :ref:`pylab_examples-psd_demo3`. +:ref:`sphx_glr_gallery_pylab_examples_psd_demo2.py`. and :ref:`sphx_glr_gallery_pylab_examples_psd_demo3.py`. The changes should increase MATLAB compatibility and increase scaling options. diff --git a/doc/users/prev_whats_new/whats_new_0.99.rst b/doc/users/prev_whats_new/whats_new_0.99.rst index bc8d0e8cea9f..e12059562a71 100644 --- a/doc/users/prev_whats_new/whats_new_0.99.rst +++ b/doc/users/prev_whats_new/whats_new_0.99.rst @@ -11,11 +11,11 @@ New in matplotlib 0.99 New documentation ----------------- -Jae-Joon Lee has written two new guides :ref:`plotting-guide-legend` +Jae-Joon Lee has written two new guides :ref:`sphx_glr_tutorials_02_intermediate_legend_guide.py` and :ref:`plotting-guide-annotation`. Michael Sarahan has written -:ref:`image_tutorial`. John Hunter has written two new tutorials on -working with paths and transformations: :ref:`path_tutorial` and -:ref:`transforms_tutorial`. +:ref:`sphx_glr_tutorials_01_introductory_images.py`. John Hunter has written two new tutorials on +working with paths and transformations: :ref:`sphx_glr_tutorials_03_advanced_path_tutorial.py` and +:ref:`sphx_glr_tutorials_03_advanced_transforms_tutorial.py`. .. _whats-new-mplot3d: @@ -65,7 +65,7 @@ that denote the data limits -- in various arbitrary locations. No longer are your axis lines constrained to be a simple rectangle around the figure -- you can turn on or off left, bottom, right and top, as well as "detach" the spine to offset it away from the data. See -:ref:`pylab_examples-spine_placement_demo` and +:ref:`sphx_glr_gallery_pylab_examples_spine_placement_demo.py` and :class:`matplotlib.spines.Spine`. .. figure:: ../../gallery/pyplots/images/sphx_glr_whats_new_99_spines_001.png diff --git a/doc/users/prev_whats_new/whats_new_1.0.rst b/doc/users/prev_whats_new/whats_new_1.0.rst index dea95bde344f..5b376298e7b6 100644 --- a/doc/users/prev_whats_new/whats_new_1.0.rst +++ b/doc/users/prev_whats_new/whats_new_1.0.rst @@ -23,7 +23,7 @@ Sophisticated subplot grid layout Jae-Joon Lee has written :mod:`~matplotlib.gridspec`, a new module for doing complex subplot layouts, featuring row and column spans and -more. See :ref:`gridspec-guide` for a tutorial overview. +more. See :ref:`sphx_glr_tutorials_02_intermediate_gridspec.py` for a tutorial overview. .. figure:: ../../gallery/userdemo/images/sphx_glr_demo_gridspec01_000.png :target: ../../gallery/userdemo/demo_gridspec01.html @@ -44,7 +44,7 @@ indexing (starts with 0). e.g.:: fig, axarr = plt.subplots(2, 2) axarr[0,0].plot([1,2,3]) # upper, left -See :ref:`pylab_examples-subplots_demo` for several code examples. +See :ref:`sphx_glr_gallery_pylab_examples_subplot_demo.py` for several code examples. Contour fixes and and triplot --------------------------------- diff --git a/doc/users/prev_whats_new/whats_new_1.1.rst b/doc/users/prev_whats_new/whats_new_1.1.rst index bb8670efb073..33477ad2ce6a 100644 --- a/doc/users/prev_whats_new/whats_new_1.1.rst +++ b/doc/users/prev_whats_new/whats_new_1.1.rst @@ -17,8 +17,8 @@ Sankey Diagrams Kevin Davies has extended Yannick Copin's original Sankey example into a module (:mod:`~matplotlib.sankey`) and provided new examples -(:ref:`api-sankey_basics`, :ref:`api-sankey_links`, -:ref:`api-sankey_rankine`). +(:ref:`sphx_glr_gallery_api_sankey_basics.py`, :ref:`sphx_glr_gallery_api_sankey_links.py`, +:ref:`sphx_glr_gallery_api_sankey_rankine.py`). .. figure:: ../../gallery/api/images/sphx_glr_sankey_rankine_001.png :target: ../../gallery/api/sankey_rankine.html @@ -36,7 +36,7 @@ animated figures. The :mod:`~matplotlib.animation` module is intended to replace the backend-specific examples formerly in the :ref:`examples-index` listings. Examples using the new framework are in :ref:`animation-examples-index`; see the entrancing :ref:`double -pendulum ` which uses +pendulum ` which uses :meth:`matplotlib.animation.Animation.save` to create the movie below. .. raw:: html @@ -87,7 +87,7 @@ The usage of this functionality can be as simple as :: and it will adjust the spacing between subplots so that the axis labels do not overlap with neighboring subplots. A -:ref:`plotting-guide-tight-layout` has been created to show how to use +:ref:`sphx_glr_tutorials_02_intermediate_tight_layout_guide.py` has been created to show how to use this new tool. PyQT4, PySide, and IPython @@ -116,7 +116,7 @@ legends for complex plots such as :meth:`~matplotlib.pyplot.stem` plots will now display correctly. Second, the 'best' placement of a legend has been improved in the presence of NANs. -See the :ref:`plotting-guide-legend` for more detailed explanation and +See the :ref:`sphx_glr_tutorials_02_intermediate_legend_guide.py` for more detailed explanation and examples. .. figure:: ../../gallery/pylab_examples/images/sphx_glr_legend_demo4_001.png diff --git a/doc/users/prev_whats_new/whats_new_1.2.rst b/doc/users/prev_whats_new/whats_new_1.2.rst index 568759cf4d1b..48c19f090fa5 100644 --- a/doc/users/prev_whats_new/whats_new_1.2.rst +++ b/doc/users/prev_whats_new/whats_new_1.2.rst @@ -39,7 +39,7 @@ PGF/TikZ backend Peter Würtz wrote a backend that allows matplotlib to export figures as drawing commands for LaTeX. These can be processed by PdfLaTeX, XeLaTeX or LuaLaTeX using the PGF/TikZ package. Usage examples and documentation are -found in :ref:`pgf-tutorial`. +found in :ref:`sphx_glr_tutorials_text_pgf.py`. .. image:: /_static/pgf_preamble.* diff --git a/doc/users/prev_whats_new/whats_new_1.4.rst b/doc/users/prev_whats_new/whats_new_1.4.rst index ab12024467e3..7aac6495c2e0 100644 --- a/doc/users/prev_whats_new/whats_new_1.4.rst +++ b/doc/users/prev_whats_new/whats_new_1.4.rst @@ -82,8 +82,8 @@ with :func:`~matplotlib.Axes.bxp`. Lastly, each artist (e.g., the box, outliers, cap, notches) can now be toggled on or off and their styles can be passed in through individual kwargs. See the examples: -:ref:`statistics-boxplot` and -:ref:`statistics-bxp` +:ref:`sphx_glr_gallery_statistics_boxplot.py` and +:ref:`sphx_glr_gallery_statistics_bxp.py` Added a bool kwarg, :code:`manage_xticks`, which if False disables the management of the ticks and limits on the x-axis by :func:`~matplotlib.axes.Axes.bxp`. @@ -410,7 +410,7 @@ instead of ``:context:`` any time you want to reset the context. Legend and PathEffects documentation ------------------------------------ -The :ref:`plotting-guide-legend` and :ref:`patheffects-guide` have both been +The :ref:`sphx_glr_tutorials_02_intermediate_legend_guide.py` and :ref:`sphx_glr_tutorials_03_advanced_patheffects_guide.py` have both been updated to better reflect the full potential of each of these powerful features. diff --git a/doc/users/prev_whats_new/whats_new_1.5.rst b/doc/users/prev_whats_new/whats_new_1.5.rst index f172a78d3841..94f70d33047e 100644 --- a/doc/users/prev_whats_new/whats_new_1.5.rst +++ b/doc/users/prev_whats_new/whats_new_1.5.rst @@ -679,7 +679,7 @@ mutually exclusive inside that group. For tools derived from that are called automatically whenever it is toggled. -A full example is located in :ref:`user_interfaces-toolmanager` +A full example is located in :ref:`sphx_glr_gallery_user_interfaces_toolmanager_sgskip.py` cbook.is_sequence_of_strings recognizes string objects diff --git a/doc/users/pyplot_tutorial.rst b/doc/users/pyplot_tutorial.rst deleted file mode 100644 index f588c65bc418..000000000000 --- a/doc/users/pyplot_tutorial.rst +++ /dev/null @@ -1,342 +0,0 @@ -.. _pyplot-tutorial: - -*************** -Pyplot tutorial -*************** - -:mod:`matplotlib.pyplot` is a collection of command style functions -that make matplotlib work like MATLAB. -Each ``pyplot`` function makes -some change to a figure: e.g., creates a figure, creates a plotting area -in a figure, plots some lines in a plotting area, decorates the plot -with labels, etc. In :mod:`matplotlib.pyplot` various states are preserved -across function calls, so that it keeps track of things like -the current figure and plotting area, and the plotting -functions are directed to the current axes (please note that "axes" here -and in most places in the documentation refers to the *axes* -`part of a figure `__ -and not the strict mathematical term for more than one axis). - -.. figure:: ../gallery/pyplots/images/sphx_glr_pyplot_simple_001.png - :target: ../gallery/pyplots/pyplot_simple.html - :align: center - :scale: 50 - - Pyplot Simple - -You may be wondering why the x-axis ranges from 0-3 and the y-axis -from 1-4. If you provide a single list or array to the -:func:`~matplotlib.pyplot.plot` command, matplotlib assumes it is a -sequence of y values, and automatically generates the x values for -you. Since python ranges start with 0, the default x vector has the -same length as y but starts with 0. Hence the x data are -``[0,1,2,3]``. - -:func:`~matplotlib.pyplot.plot` is a versatile command, and will take -an arbitrary number of arguments. For example, to plot x versus y, -you can issue the command:: - - plt.plot([1, 2, 3, 4], [1, 4, 9, 16]) - -For every x, y pair of arguments, there is an optional third argument -which is the format string that indicates the color and line type of -the plot. The letters and symbols of the format string are from -MATLAB, and you concatenate a color string with a line style string. -The default format string is 'b-', which is a solid blue line. For -example, to plot the above with red circles, you would issue - -.. figure:: ../gallery/pyplots/images/sphx_glr_pyplot_formatstr_001.png - :target: ../gallery/pyplots/pyplot_formatstr.html - :align: center - :scale: 50 - - Pyplot Formatstr - -See the :func:`~matplotlib.pyplot.plot` documentation for a complete -list of line styles and format strings. The -:func:`~matplotlib.pyplot.axis` command in the example above takes a -list of ``[xmin, xmax, ymin, ymax]`` and specifies the viewport of the -axes. - -If matplotlib were limited to working with lists, it would be fairly -useless for numeric processing. Generally, you will use `numpy -`_ arrays. In fact, all sequences are -converted to numpy arrays internally. The example below illustrates a -plotting several lines with different format styles in one command -using arrays. - -.. figure:: ../gallery/pyplots/images/sphx_glr_pyplot_three_001.png - :target: ../gallery/pyplots/pyplot_three.html - :align: center - :scale: 50 - - Pyplot Three - -.. _controlling-line-properties: - -Controlling line properties -=========================== - -Lines have many attributes that you can set: linewidth, dash style, -antialiased, etc; see :class:`matplotlib.lines.Line2D`. There are -several ways to set line properties - -* Use keyword args:: - - plt.plot(x, y, linewidth=2.0) - - -* Use the setter methods of a ``Line2D`` instance. ``plot`` returns a list - of ``Line2D`` objects; e.g., ``line1, line2 = plot(x1, y1, x2, y2)``. In the code - below we will suppose that we have only - one line so that the list returned is of length 1. We use tuple unpacking with - ``line,`` to get the first element of that list:: - - line, = plt.plot(x, y, '-') - line.set_antialiased(False) # turn off antialising - -* Use the :func:`~matplotlib.pyplot.setp` command. The example below - uses a MATLAB-style command to set multiple properties - on a list of lines. ``setp`` works transparently with a list of objects - or a single object. You can either use python keyword arguments or - MATLAB-style string/value pairs:: - - lines = plt.plot(x1, y1, x2, y2) - # use keyword args - plt.setp(lines, color='r', linewidth=2.0) - # or MATLAB style string value pairs - plt.setp(lines, 'color', 'r', 'linewidth', 2.0) - - -Here are the available :class:`~matplotlib.lines.Line2D` properties. - -====================== ================================================== -Property Value Type -====================== ================================================== -alpha float -animated [True | False] -antialiased or aa [True | False] -clip_box a matplotlib.transform.Bbox instance -clip_on [True | False] -clip_path a Path instance and a Transform instance, a Patch -color or c any matplotlib color -contains the hit testing function -dash_capstyle [``'butt'`` | ``'round'`` | ``'projecting'``] -dash_joinstyle [``'miter'`` | ``'round'`` | ``'bevel'``] -dashes sequence of on/off ink in points -data (np.array xdata, np.array ydata) -figure a matplotlib.figure.Figure instance -label any string -linestyle or ls [ ``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'steps'`` | ...] -linewidth or lw float value in points -lod [True | False] -marker [ ``'+'`` | ``','`` | ``'.'`` | ``'1'`` | ``'2'`` | ``'3'`` | ``'4'`` ] -markeredgecolor or mec any matplotlib color -markeredgewidth or mew float value in points -markerfacecolor or mfc any matplotlib color -markersize or ms float -markevery [ None | integer | (startind, stride) ] -picker used in interactive line selection -pickradius the line pick selection radius -solid_capstyle [``'butt'`` | ``'round'`` | ``'projecting'``] -solid_joinstyle [``'miter'`` | ``'round'`` | ``'bevel'``] -transform a matplotlib.transforms.Transform instance -visible [True | False] -xdata np.array -ydata np.array -zorder any number -====================== ================================================== - -To get a list of settable line properties, call the -:func:`~matplotlib.pyplot.setp` function with a line or lines -as argument - -.. sourcecode:: ipython - - In [69]: lines = plt.plot([1, 2, 3]) - - In [70]: plt.setp(lines) - alpha: float - animated: [True | False] - antialiased or aa: [True | False] - ...snip - -.. _multiple-figs-axes: - -Working with multiple figures and axes -====================================== - - -MATLAB, and :mod:`~matplotlib.pyplot`, have the concept of the current -figure and the current axes. All plotting commands apply to the -current axes. The function :func:`~matplotlib.pyplot.gca` returns the -current axes (a :class:`matplotlib.axes.Axes` instance), and -:func:`~matplotlib.pyplot.gcf` returns the current figure -(:class:`matplotlib.figure.Figure` instance). Normally, you don't have -to worry about this, because it is all taken care of behind the -scenes. Below is a script to create two subplots. - -.. figure:: ../gallery/pyplots/images/sphx_glr_pyplot_two_subplots_001.png - :target: ../gallery/pyplots/pyplot_two_subplots.html - :align: center - :scale: 50 - - Pyplot Two Subplots - -The :func:`~matplotlib.pyplot.figure` command here is optional because -``figure(1)`` will be created by default, just as a ``subplot(111)`` -will be created by default if you don't manually specify any axes. The -:func:`~matplotlib.pyplot.subplot` command specifies ``numrows, -numcols, fignum`` where ``fignum`` ranges from 1 to -``numrows*numcols``. The commas in the ``subplot`` command are -optional if ``numrows*numcols<10``. So ``subplot(211)`` is identical -to ``subplot(2, 1, 1)``. You can create an arbitrary number of subplots -and axes. If you want to place an axes manually, i.e., not on a -rectangular grid, use the :func:`~matplotlib.pyplot.axes` command, -which allows you to specify the location as ``axes([left, bottom, -width, height])`` where all values are in fractional (0 to 1) -coordinates. See :ref:`pylab_examples-axes_demo` for an example of -placing axes manually and :ref:`pylab_examples-subplots_demo` for an -example with lots of subplots. - - -You can create multiple figures by using multiple -:func:`~matplotlib.pyplot.figure` calls with an increasing figure -number. Of course, each figure can contain as many axes and subplots -as your heart desires:: - - import matplotlib.pyplot as plt - plt.figure(1) # the first figure - plt.subplot(211) # the first subplot in the first figure - plt.plot([1, 2, 3]) - plt.subplot(212) # the second subplot in the first figure - plt.plot([4, 5, 6]) - - - plt.figure(2) # a second figure - plt.plot([4, 5, 6]) # creates a subplot(111) by default - - plt.figure(1) # figure 1 current; subplot(212) still current - plt.subplot(211) # make subplot(211) in figure1 current - plt.title('Easy as 1, 2, 3') # subplot 211 title - -You can clear the current figure with :func:`~matplotlib.pyplot.clf` -and the current axes with :func:`~matplotlib.pyplot.cla`. If you find -it annoying that states (specifically the current image, figure and axes) -are being maintained for you behind the scenes, don't despair: this is just a thin -stateful wrapper around an object oriented API, which you can use -instead (see :ref:`artist-tutorial`) - -If you are making lots of figures, you need to be aware of one -more thing: the memory required for a figure is not completely -released until the figure is explicitly closed with -:func:`~matplotlib.pyplot.close`. Deleting all references to the -figure, and/or using the window manager to kill the window in which -the figure appears on the screen, is not enough, because pyplot -maintains internal references until :func:`~matplotlib.pyplot.close` -is called. - -.. _working-with-text: - -Working with text -================= - -The :func:`~matplotlib.pyplot.text` command can be used to add text in -an arbitrary location, and the :func:`~matplotlib.pyplot.xlabel`, -:func:`~matplotlib.pyplot.ylabel` and :func:`~matplotlib.pyplot.title` -are used to add text in the indicated locations (see :ref:`text-intro` -for a more detailed example) - -.. figure:: ../gallery/pyplots/images/sphx_glr_pyplot_text_001.png - :target: ../gallery/pyplots/pyplot_text.html - :align: center - :scale: 50 - - Pyplot Text - - -All of the :func:`~matplotlib.pyplot.text` commands return an -:class:`matplotlib.text.Text` instance. Just as with with lines -above, you can customize the properties by passing keyword arguments -into the text functions or using :func:`~matplotlib.pyplot.setp`:: - - t = plt.xlabel('my data', fontsize=14, color='red') - -These properties are covered in more detail in :ref:`text-properties`. - - -Using mathematical expressions in text --------------------------------------- - -matplotlib accepts TeX equation expressions in any text expression. -For example to write the expression :math:`\sigma_i=15` in the title, -you can write a TeX expression surrounded by dollar signs:: - - plt.title(r'$\sigma_i=15$') - -The ``r`` preceding the title string is important -- it signifies -that the string is a *raw* string and not to treat backslashes as -python escapes. matplotlib has a built-in TeX expression parser and -layout engine, and ships its own math fonts -- for details see -:ref:`mathtext-tutorial`. Thus you can use mathematical text across platforms -without requiring a TeX installation. For those who have LaTeX and -dvipng installed, you can also use LaTeX to format your text and -incorporate the output directly into your display figures or saved -postscript -- see :ref:`usetex-tutorial`. - - -Annotating text ---------------- - -The uses of the basic :func:`~matplotlib.pyplot.text` command above -place text at an arbitrary position on the Axes. A common use for -text is to annotate some feature of the plot, and the -:func:`~matplotlib.pyplot.annotate` method provides helper -functionality to make annotations easy. In an annotation, there are -two points to consider: the location being annotated represented by -the argument ``xy`` and the location of the text ``xytext``. Both of -these arguments are ``(x,y)`` tuples. - -.. figure:: ../gallery/pyplots/images/sphx_glr_pyplot_annotate_001.png - :target: ../gallery/pyplots/pyplot_annotate.html - :align: center - :scale: 50 - - Pyplot Annotate - -In this basic example, both the ``xy`` (arrow tip) and ``xytext`` -locations (text location) are in data coordinates. There are a -variety of other coordinate systems one can choose -- see -:ref:`annotations-tutorial` and :ref:`plotting-guide-annotation` for -details. More examples can be found in -:ref:`pylab_examples-annotation_demo`. - - -Logarithmic and other nonlinear axes -==================================== - -:mod:`matplotlib.pyplot` supports not only linear axis scales, but also -logarithmic and logit scales. This is commonly used if data spans many orders -of magnitude. Changing the scale of an axis is easy: - - plt.xscale('log') - -An example of four plots with the same data and different scales for the y axis -is shown below. - -.. figure:: ../gallery/pyplots/images/sphx_glr_pyplot_scales_001.png - :target: ../gallery/pyplots/pyplot_scales.html - :align: center - :scale: 50 - - Pyplot Scales - -It is also possible to add your own scale, see :ref:`adding-new-scales` for -details. - - - - - - - diff --git a/doc/users/recipes.rst b/doc/users/recipes.rst deleted file mode 100644 index 4b413b757b43..000000000000 --- a/doc/users/recipes.rst +++ /dev/null @@ -1,378 +0,0 @@ -.. _recipes: - -******************** -Our Favorite Recipes -******************** - -Here is a collection of short tutorials, examples and code snippets -that illustrate some of the useful idioms and tricks to make snazzier -figures and overcome some matplotlib warts. - - -Sharing axis limits and views -============================= - -It's common to make two or more plots which share an axis, e.g., two -subplots with time as a common axis. When you pan and zoom around on -one, you want the other to move around with you. To facilitate this, -matplotlib Axes support a ``sharex`` and ``sharey`` attribute. When -you create a :func:`~matplotlib.pyplot.subplot` or -:func:`~matplotlib.pyplot.axes` instance, you can pass in a keyword -indicating what axes you want to share with - -.. sourcecode:: ipython - - In [96]: t = np.arange(0, 10, 0.01) - - In [97]: ax1 = plt.subplot(211) - - In [98]: ax1.plot(t, np.sin(2*np.pi*t)) - Out[98]: [] - - In [99]: ax2 = plt.subplot(212, sharex=ax1) - - In [100]: ax2.plot(t, np.sin(4*np.pi*t)) - Out[100]: [] - -Easily creating subplots -======================== - -In early versions of matplotlib, if you wanted to use the pythonic API -and create a figure instance and from that create a grid of subplots, -possibly with shared axes, it involved a fair amount of boilerplate -code. e.g. - -.. sourcecode:: python - - # old style - fig = plt.figure() - ax1 = fig.add_subplot(221) - ax2 = fig.add_subplot(222, sharex=ax1, sharey=ax1) - ax3 = fig.add_subplot(223, sharex=ax1, sharey=ax1) - ax3 = fig.add_subplot(224, sharex=ax1, sharey=ax1) - -Fernando Perez has provided a nice top level method to create in -:func:`~matplotlib.pyplots.subplots` (note the "s" at the end) -everything at once, and turn on x and y sharing for the whole bunch. -You can either unpack the axes individually:: - - # new style method 1; unpack the axes - fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, sharex=True, sharey=True) - ax1.plot(x) - -or get them back as a numrows x numcolumns object array which supports -numpy indexing:: - - # new style method 2; use an axes array - fig, axs = plt.subplots(2, 2, sharex=True, sharey=True) - axs[0,0].plot(x) - - - -Fixing common date annoyances -============================= - - -.. plot:: - :nofigs: - :context: - - # clear the state for context use below - plt.close('all') - -matplotlib allows you to natively plots python datetime instances, and -for the most part does a good job picking tick locations and string -formats. There are a couple of things it does not handle so -gracefully, and here are some tricks to help you work around them. -We'll load up some sample date data which contains datetime.date -objects in a numpy record array:: - - In [63]: datafile = cbook.get_sample_data('goog.npz') - - In [64]: r = np.load(datafile)['price_data'].view(np.recarray) - - In [65]: r.dtype - Out[65]: dtype([('date', '] - -you will see that the x tick labels are all squashed together. - -.. plot:: - :context: - - import matplotlib.cbook as cbook - with cbook.get_sample_data('goog.npz') as datafile: - r = np.load(datafile)['price_data'].view(np.recarray) - # Matplotlib prefers datetime instead of np.datetime64. - date = r.date.astype('O') - plt.figure() - plt.plot(date, r.close) - plt.title('Default date handling can cause overlapping labels') - -Another annoyance is that if you hover the mouse over the window and -look in the lower right corner of the matplotlib toolbar -(:ref:`navigation-toolbar`) at the x and y coordinates, you see that -the x locations are formatted the same way the tick labels are, e.g., -"Dec 2004". What we'd like is for the location in the toolbar to have -a higher degree of precision, e.g., giving us the exact date out mouse is -hovering over. To fix the first problem, we can use -:func:`matplotlib.figure.Figure.autofmt_xdate` and to fix the second -problem we can use the ``ax.fmt_xdata`` attribute which can be set to -any function that takes a scalar and returns a string. matplotlib has -a number of date formatters built in, so we'll use one of those. - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig, ax = plt.subplots(1) - ax.plot(date, r.close) - - # rotate and align the tick labels so they look better - fig.autofmt_xdate() - - # use a more precise date string for the x axis locations in the - # toolbar - import matplotlib.dates as mdates - ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d') - plt.title('fig.autofmt_xdate fixes the labels') - -Now when you hover your mouse over the plotted data, you'll see date -format strings like 2004-12-01 in the toolbar. - -Fill Between and Alpha -====================== - -The :meth:`~matplotlib.axes.Axes.fill_between` function generates a -shaded region between a min and max boundary that is useful for -illustrating ranges. It has a very handy ``where`` argument to -combine filling with logical ranges, e.g., to just fill in a curve over -some threshold value. - -At its most basic level, ``fill_between`` can be use to enhance a -graphs visual appearance. Let's compare two graphs of a financial -times with a simple line plot on the left and a filled line on the -right. - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import numpy as np - - import matplotlib.cbook as cbook - - # load up some sample financial data - with cbook.get_sample_data('goog.npz') as datafile: - r = np.load(datafile)['price_data'].view(np.recarray) - # Matplotlib prefers datetime instead of np.datetime64. - date = r.date.astype('O') - # create two subplots with the shared x and y axes - fig, (ax1, ax2) = plt.subplots(1,2, sharex=True, sharey=True) - - pricemin = r.close.min() - - ax1.plot(date, r.close, lw=2) - ax2.fill_between(date, pricemin, r.close, facecolor='blue', alpha=0.5) - - for ax in ax1, ax2: - ax.grid(True) - - ax1.set_ylabel('price') - for label in ax2.get_yticklabels(): - label.set_visible(False) - - fig.suptitle('Google (GOOG) daily closing price') - fig.autofmt_xdate() - -The alpha channel is not necessary here, but it can be used to soften -colors for more visually appealing plots. In other examples, as we'll -see below, the alpha channel is functionally useful as the shaded -regions can overlap and alpha allows you to see both. Note that the -postscript format does not support alpha (this is a postscript -limitation, not a matplotlib limitation), so when using alpha save -your figures in PNG, PDF or SVG. - -Our next example computes two populations of random walkers with a -different mean and standard deviation of the normal distributions from -which the steps are drawn. We use shared regions to plot +/- one -standard deviation of the mean position of the population. Here the -alpha channel is useful, not just aesthetic. - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import numpy as np - - Nsteps, Nwalkers = 100, 250 - t = np.arange(Nsteps) - - # an (Nsteps x Nwalkers) array of random walk steps - S1 = 0.002 + 0.01*np.random.randn(Nsteps, Nwalkers) - S2 = 0.004 + 0.02*np.random.randn(Nsteps, Nwalkers) - - # an (Nsteps x Nwalkers) array of random walker positions - X1 = S1.cumsum(axis=0) - X2 = S2.cumsum(axis=0) - - - # Nsteps length arrays empirical means and standard deviations of both - # populations over time - mu1 = X1.mean(axis=1) - sigma1 = X1.std(axis=1) - mu2 = X2.mean(axis=1) - sigma2 = X2.std(axis=1) - - # plot it! - fig, ax = plt.subplots(1) - ax.plot(t, mu1, lw=2, label='mean population 1', color='blue') - ax.plot(t, mu2, lw=2, label='mean population 2', color='yellow') - ax.fill_between(t, mu1+sigma1, mu1-sigma1, facecolor='blue', alpha=0.5) - ax.fill_between(t, mu2+sigma2, mu2-sigma2, facecolor='yellow', alpha=0.5) - ax.set_title('random walkers empirical $\mu$ and $\pm \sigma$ interval') - ax.legend(loc='upper left') - ax.set_xlabel('num steps') - ax.set_ylabel('position') - ax.grid() - - -The ``where`` keyword argument is very handy for highlighting certain -regions of the graph. ``where`` takes a boolean mask the same length -as the x, ymin and ymax arguments, and only fills in the region where -the boolean mask is True. In the example below, we simulate a single -random walker and compute the analytic mean and standard deviation of -the population positions. The population mean is shown as the black -dashed line, and the plus/minus one sigma deviation from the mean is -shown as the yellow filled region. We use the where mask -``X>upper_bound`` to find the region where the walker is above the one -sigma boundary, and shade that region blue. - -.. plot:: - :include-source: - - np.random.seed(1234) - - Nsteps = 500 - t = np.arange(Nsteps) - - mu = 0.002 - sigma = 0.01 - - # the steps and position - S = mu + sigma*np.random.randn(Nsteps) - X = S.cumsum() - - # the 1 sigma upper and lower analytic population bounds - lower_bound = mu*t - sigma*np.sqrt(t) - upper_bound = mu*t + sigma*np.sqrt(t) - - fig, ax = plt.subplots(1) - ax.plot(t, X, lw=2, label='walker position', color='blue') - ax.plot(t, mu*t, lw=1, label='population mean', color='black', ls='--') - ax.fill_between(t, lower_bound, upper_bound, facecolor='yellow', alpha=0.5, - label='1 sigma range') - ax.legend(loc='upper left') - - # here we use the where argument to only fill the region where the - # walker is above the population 1 sigma boundary - ax.fill_between(t, upper_bound, X, where=X>upper_bound, facecolor='blue', alpha=0.5) - ax.set_xlabel('num steps') - ax.set_ylabel('position') - ax.grid() - - -Another handy use of filled regions is to highlight horizontal or -vertical spans of an axes -- for that matplotlib has some helper -functions :meth:`~matplotlib.axes.Axes.axhspan` and -:meth:`~matplotlib.axes.Axes.axvspan` and example -:ref:`pylab_examples-axhspan_demo`. - - -Transparent, fancy legends -========================== - -Sometimes you know what your data looks like before you plot it, and -may know for instance that there won't be much data in the upper right -hand corner. Then you can safely create a legend that doesn't overlay -your data:: - - ax.legend(loc='upper right') - -Other times you don't know where your data is, and loc='best' will try -and place the legend:: - - ax.legend(loc='best') - -but still, your legend may overlap your data, and in these cases it's -nice to make the legend frame transparent. - - -.. plot:: - :include-source: - - np.random.seed(1234) - fig, ax = plt.subplots(1) - ax.plot(np.random.randn(300), 'o-', label='normal distribution') - ax.plot(np.random.rand(300), 's-', label='uniform distribution') - ax.set_ylim(-3, 3) - ax.legend(loc='best', fancybox=True, framealpha=0.5) - - ax.set_title('fancy, transparent legends') - - -Placing text boxes -================== - -When decorating axes with text boxes, two useful tricks are to place -the text in axes coordinates (see :ref:`transforms_tutorial`), so the -text doesn't move around with changes in x or y limits. You can also -use the ``bbox`` property of text to surround the text with a -:class:`~matplotlib.patches.Patch` instance -- the ``bbox`` keyword -argument takes a dictionary with keys that are Patch properties. - -.. plot:: - :include-source: - - np.random.seed(1234) - fig, ax = plt.subplots(1) - x = 30*np.random.randn(10000) - mu = x.mean() - median = np.median(x) - sigma = x.std() - textstr = '$\mu=%.2f$\n$\mathrm{median}=%.2f$\n$\sigma=%.2f$'%(mu, median, sigma) - - ax.hist(x, 50) - # these are matplotlib.patch.Patch properties - props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) - - # place a text box in upper left in axes coords - ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=14, - verticalalignment='top', bbox=props) diff --git a/doc/users/screenshots.rst b/doc/users/screenshots.rst index 93cd37b873ce..83f7f21e4f62 100644 --- a/doc/users/screenshots.rst +++ b/doc/users/screenshots.rst @@ -326,7 +326,7 @@ fonts. See the :mod:`matplotlib.mathtext` module for additional details. Matplotlib's mathtext infrastructure is an independent implementation and does not require TeX or any external packages installed on your computer. See -the tutorial at :ref:`mathtext-tutorial`. +the tutorial at :ref:`sphx_glr_tutorials_text_mathtext.py`. .. _screenshots_tex_demo: @@ -361,11 +361,11 @@ to plot the spectrogram of one of the EEG channels. For examples of how to embed matplotlib in different toolkits, see: - * :ref:`user_interfaces-embedding_in_gtk2` - * :ref:`user_interfaces-embedding_in_wx2` - * :ref:`user_interfaces-mpl_with_glade` - * :ref:`user_interfaces-embedding_in_qt4` - * :ref:`user_interfaces-embedding_in_tk` + * :ref:`sphx_glr_gallery_user_interfaces_embedding_in_gtk2_sgskip.py` + * :ref:`sphx_glr_gallery_user_interfaces_embedding_in_wx2_sgskip.py` + * :ref:`sphx_glr_gallery_user_interfaces_mpl_with_glade_sgskip.py` + * :ref:`sphx_glr_gallery_user_interfaces_embedding_in_qt4_sgskip.py` + * :ref:`sphx_glr_gallery_user_interfaces_embedding_in_tk_sgskip.py` XKCD-style sketch plots ======================= diff --git a/doc/users/shell.rst b/doc/users/shell.rst index 82822842e763..7635ccda971e 100644 --- a/doc/users/shell.rst +++ b/doc/users/shell.rst @@ -92,7 +92,7 @@ are going to need to understand what a matplotlib backend is With the TkAgg backend, which uses the Tkinter user interface toolkit, you can use matplotlib from an arbitrary non-gui python shell. Just set your ``backend : TkAgg`` and ``interactive : True`` in your -:file:`matplotlibrc` file (see :ref:`customizing-matplotlib`) and fire +:file:`matplotlibrc` file (see :ref:`sphx_glr_tutorials_01_introductory_customizing.py`) and fire up python. Then:: >>> from pylab import * diff --git a/doc/users/text_props.rst b/doc/users/text_props.rst deleted file mode 100644 index 75e3496b9cba..000000000000 --- a/doc/users/text_props.rst +++ /dev/null @@ -1,162 +0,0 @@ -.. _text-properties: - -============================ - Text properties and layout -============================ - -The :class:`matplotlib.text.Text` instances have a variety of -properties which can be configured via keyword arguments to the text -commands (e.g., :func:`~matplotlib.pyplot.title`, -:func:`~matplotlib.pyplot.xlabel` and :func:`~matplotlib.pyplot.text`). - -========================== ====================================================================================================================== -Property Value Type -========================== ====================================================================================================================== -alpha `float` -backgroundcolor any matplotlib :ref:`color ` -bbox `~matplotlib.patches.Rectangle` prop dict plus key ``'pad'`` which is a pad in points -clip_box a matplotlib.transform.Bbox instance -clip_on [True | False] -clip_path a `~matplotlib.path.Path` instance and a `~matplotlib.transforms.Transform` instance, a `~matplotlib.patches.Patch` -color any matplotlib :ref:`color ` -family [ ``'serif'`` | ``'sans-serif'`` | ``'cursive'`` | ``'fantasy'`` | ``'monospace'`` ] -fontproperties a `~matplotlib.font_manager.FontProperties` instance -horizontalalignment or ha [ ``'center'`` | ``'right'`` | ``'left'`` ] -label any string -linespacing `float` -multialignment [``'left'`` | ``'right'`` | ``'center'`` ] -name or fontname string e.g., [``'Sans'`` | ``'Courier'`` | ``'Helvetica'`` ...] -picker [None|float|boolean|callable] -position (x, y) -rotation [ angle in degrees | ``'vertical'`` | ``'horizontal'`` ] -size or fontsize [ size in points | relative size, e.g., ``'smaller'``, ``'x-large'`` ] -style or fontstyle [ ``'normal'`` | ``'italic'`` | ``'oblique'`` ] -text string or anything printable with '%s' conversion -transform a `~matplotlib.transforms.Transform` instance -variant [ ``'normal'`` | ``'small-caps'`` ] -verticalalignment or va [ ``'center'`` | ``'top'`` | ``'bottom'`` | ``'baseline'`` ] -visible [True | False] -weight or fontweight [ ``'normal'`` | ``'bold'`` | ``'heavy'`` | ``'light'`` | ``'ultrabold'`` | ``'ultralight'``] -x `float` -y `float` -zorder any number -========================== ====================================================================================================================== - - -You can lay out text with the alignment arguments -``horizontalalignment``, ``verticalalignment``, and -``multialignment``. ``horizontalalignment`` controls whether the x -positional argument for the text indicates the left, center or right -side of the text bounding box. ``verticalalignment`` controls whether -the y positional argument for the text indicates the bottom, center or -top side of the text bounding box. ``multialignment``, for newline -separated strings only, controls whether the different lines are left, -center or right justified. Here is an example which uses the -:func:`~matplotlib.pyplot.text` command to show the various alignment -possibilities. The use of ``transform=ax.transAxes`` throughout the -code indicates that the coordinates are given relative to the axes -bounding box, with 0,0 being the lower left of the axes and 1,1 the -upper right. - -.. figure:: ../gallery/pyplots/images/sphx_glr_text_layout_001.png - :target: ../gallery/pyplots/text_layout.html - :align: center - :scale: 50 - - Text Layout - - -============== - Default Font -============== - -The base default font is controlled by a set of rcParams: - -+---------------------+----------------------------------------------------+ -| rcParam | usage | -+=====================+====================================================+ -| ``'font.family'`` | List of either names of font or ``{'cursive', | -| | 'fantasy', 'monospace', 'sans', 'sans serif', | -| | 'sans-serif', 'serif'}``. | -| | | -+---------------------+----------------------------------------------------+ -| ``'font.style'`` | The default style, ex ``'normal'``, | -| | ``'italic'``. | -| | | -+---------------------+----------------------------------------------------+ -| ``'font.variant'`` | Default variant, ex ``'normal'``, ``'small-caps'`` | -| | (untested) | -+---------------------+----------------------------------------------------+ -| ``'font.stretch'`` | Default stretch, ex ``'normal'``, ``'condensed'`` | -| | (incomplete) | -| | | -+---------------------+----------------------------------------------------+ -| ``'font.weight'`` | Default weight. Either string or integer | -| | | -| | | -+---------------------+----------------------------------------------------+ -| ``'font.size'`` | Default font size in points. Relative font sizes | -| | (``'large'``, ``'x-small'``) are computed against | -| | this size. | -+---------------------+----------------------------------------------------+ - -The mapping between the family aliases (``{'cursive', 'fantasy', -'monospace', 'sans', 'sans serif', 'sans-serif', 'serif'}``) and actual font names -is controlled by the following rcParams: - - -+------------------------------------------+--------------------------------+ -| family alias | rcParam with mappings | -+==========================================+================================+ -| ``'serif'`` | ``'font.serif'`` | -+------------------------------------------+--------------------------------+ -| ``'monospace'`` | ``'font.monospace'`` | -+------------------------------------------+--------------------------------+ -| ``'fantasy'`` | ``'font.fantasy'`` | -+------------------------------------------+--------------------------------+ -| ``'cursive'`` | ``'font.cursive'`` | -+------------------------------------------+--------------------------------+ -| ``{'sans', 'sans serif', 'sans-serif'}`` | ``'font.sans-serif'`` | -+------------------------------------------+--------------------------------+ - - -which are lists of font names. - -Text with non-latin glyphs -========================== - -As of v2.0 the :ref:`default font ` contains -glyphs for many western alphabets, but still does not cover all of the -glyphs that may be required by mpl users. For example, DejaVu has no -coverage of Chinese, Korean, or Japanese. - - -To set the default font to be one that supports the code points you -need, prepend the font name to ``'font.family'`` or the desired alias -lists :: - - matplotlib.rcParams['font.sans-serif'] = ['Source Han Sans TW', 'sans-serif'] - -or set it in your :file:`.matplotlibrc` file:: - - font.sans-serif: Source Han Sans TW, Ariel, sans-serif - -To control the font used on per-artist basis use the ``'name'``, -``'fontname'`` or ``'fontproperties'`` kwargs documented :ref:`above -`. - - -On linux, `fc-list `__ can be a -useful tool to discover the font name; for example :: - - $ fc-list :lang=zh family - Noto to Sans Mono CJK TC,Noto Sans Mono CJK TC Bold - Noto Sans CJK TC,Noto Sans CJK TC Medium - Noto Sans CJK TC,Noto Sans CJK TC DemiLight - Noto Sans CJK KR,Noto Sans CJK KR Black - Noto Sans CJK TC,Noto Sans CJK TC Black - Noto Sans Mono CJK TC,Noto Sans Mono CJK TC Regular - Noto Sans CJK SC,Noto Sans CJK SC Light - -lists all of the fonts that support Chinese. - diff --git a/doc/users/tight_layout_guide.rst b/doc/users/tight_layout_guide.rst deleted file mode 100644 index 7f008901a2a8..000000000000 --- a/doc/users/tight_layout_guide.rst +++ /dev/null @@ -1,322 +0,0 @@ -.. _plotting-guide-tight-layout: - -****************** -Tight Layout guide -****************** - -*tight_layout* automatically adjusts subplot params so that the -subplot(s) fits in to the figure area. This is an experimental -feature and may not work for some cases. It only checks the extents -of ticklabels, axis labels, and titles. - - -Simple Example -============== - -In matplotlib, the location of axes (including subplots) are specified in -normalized figure coordinates. It can happen that your axis labels or -titles (or sometimes even ticklabels) go outside the figure area, and are thus -clipped. - -.. plot:: - :include-source: - :context: - - plt.rcParams['savefig.facecolor'] = "0.8" - - def example_plot(ax, fontsize=12): - ax.plot([1, 2]) - ax.locator_params(nbins=3) - ax.set_xlabel('x-label', fontsize=fontsize) - ax.set_ylabel('y-label', fontsize=fontsize) - ax.set_title('Title', fontsize=fontsize) - - plt.close('all') - fig, ax = plt.subplots() - example_plot(ax, fontsize=24) - -To prevent this, the location of axes needs to be adjusted. For -subplots, this can be done by adjusting the subplot params -(:ref:`howto-subplots-adjust`). Matplotlib v1.1 introduces a new -command :func:`~matplotlib.pyplot.tight_layout` that does this -automatically for you. - -.. plot:: - :include-source: - :context: - - plt.tight_layout() - -When you have multiple subplots, often you see labels of different -axes overlapping each other. - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2) - example_plot(ax1) - example_plot(ax2) - example_plot(ax3) - example_plot(ax4) - - -:func:`~matplotlib.pyplot.tight_layout` will also adjust spacing between -subplots to minimize the overlaps. - -.. plot:: - :include-source: - :context: - - plt.tight_layout() - -:func:`~matplotlib.pyplot.tight_layout` can take keyword arguments of -*pad*, *w_pad* and *h_pad*. These control the extra padding around the -figure border and between subplots. The pads are specified in fraction -of fontsize. - -.. plot:: - :include-source: - :context: - - plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0) - -:func:`~matplotlib.pyplot.tight_layout` will work even if the sizes of -subplots are different as far as their grid specification is -compatible. In the example below, *ax1* and *ax2* are subplots of a 2x2 -grid, while *ax3* is of a 1x2 grid. - - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig = plt.figure() - - ax1 = plt.subplot(221) - ax2 = plt.subplot(223) - ax3 = plt.subplot(122) - - example_plot(ax1) - example_plot(ax2) - example_plot(ax3) - - plt.tight_layout() - - -It works with subplots created with -:func:`~matplotlib.pyplot.subplot2grid`. In general, subplots created -from the gridspec (:ref:`gridspec-guide`) will work. - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig = plt.figure() - - ax1 = plt.subplot2grid((3, 3), (0, 0)) - ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2) - ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2) - ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) - - example_plot(ax1) - example_plot(ax2) - example_plot(ax3) - example_plot(ax4) - - plt.tight_layout() - - -Although not thoroughly tested, it seems to work for subplots with -aspect != "auto" (e.g., axes with images). - - -.. plot:: - :include-source: - :context: - - arr = np.arange(100).reshape((10,10)) - - plt.close('all') - fig = plt.figure(figsize=(5,4)) - - ax = plt.subplot(111) - im = ax.imshow(arr, interpolation="none") - - plt.tight_layout() - - -Caveats -------- - - * :func:`~matplotlib.pyplot.tight_layout` only considers ticklabels, axis - labels, and titles. Thus, other artists may be clipped and also may - overlap. - - * It assumes that the extra space needed for ticklabels, axis labels, - and titles is independent of original location of axes. This is - often true, but there are rare cases where it is not. - - * pad=0 clips some of the texts by a few pixels. This may be a bug or - a limitation of the current algorithm and it is not clear why it - happens. Meanwhile, use of pad at least larger than 0.3 is - recommended. - - - - -Use with GridSpec ------------------ - -GridSpec has its own :func:`~matplotlib.gridspec.GridSpec.tight_layout` method -(the pyplot api :func:`~matplotlib.pyplot.tight_layout` also works). - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig = plt.figure() - - import matplotlib.gridspec as gridspec - - gs1 = gridspec.GridSpec(2, 1) - ax1 = fig.add_subplot(gs1[0]) - ax2 = fig.add_subplot(gs1[1]) - - example_plot(ax1) - example_plot(ax2) - - gs1.tight_layout(fig) - - -You may provide an optional *rect* parameter, which specifies the bounding box -that the subplots will be fit inside. The coordinates must be in normalized -figure coordinates and the default is (0, 0, 1, 1). - -.. plot:: - :include-source: - :context: - - gs1.tight_layout(fig, rect=[0, 0, 0.5, 1]) - - -For example, this can be used for a figure with multiple gridspecs. - -.. plot:: - :include-source: - :context: - - gs2 = gridspec.GridSpec(3, 1) - - for ss in gs2: - ax = fig.add_subplot(ss) - example_plot(ax) - ax.set_title("") - ax.set_xlabel("") - - ax.set_xlabel("x-label", fontsize=12) - - gs2.tight_layout(fig, rect=[0.5, 0, 1, 1], h_pad=0.5) - - -We may try to match the top and bottom of two grids :: - - top = min(gs1.top, gs2.top) - bottom = max(gs1.bottom, gs2.bottom) - - gs1.update(top=top, bottom=bottom) - gs2.update(top=top, bottom=bottom) - - -While this should be mostly good enough, adjusting top and bottom -may require adjustment of hspace also. To update hspace & vspace, we -call :func:`~matplotlib.gridspec.GridSpec.tight_layout` again with updated -rect argument. Note that the rect argument specifies the area including the -ticklabels, etc. Thus, we will increase the bottom (which is 0 for the normal -case) by the difference between the *bottom* from above and the bottom of each -gridspec. Same thing for the top. - -.. plot:: - :include-source: - :context: - - top = min(gs1.top, gs2.top) - bottom = max(gs1.bottom, gs2.bottom) - - gs1.tight_layout(fig, rect=[None, 0 + (bottom-gs1.bottom), - 0.5, 1 - (gs1.top-top)]) - gs2.tight_layout(fig, rect=[0.5, 0 + (bottom-gs2.bottom), - None, 1 - (gs2.top-top)], - h_pad=0.5) - - - -Use with AxesGrid1 ------------------- - -While limited, the axes_grid1 toolkit is also supported. - - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig = plt.figure() - - from mpl_toolkits.axes_grid1 import Grid - grid = Grid(fig, rect=111, nrows_ncols=(2,2), - axes_pad=0.25, label_mode='L', - ) - - for ax in grid: - example_plot(ax) - ax.title.set_visible(False) - - plt.tight_layout() - - - -Colorbar --------- - -If you create a colorbar with the :func:`~matplotlib.pyplot.colorbar` -command, the created colorbar is an instance of Axes, *not* Subplot, so -tight_layout does not work. With Matplotlib v1.1, you may create a -colorbar as a subplot using the gridspec. - -.. plot:: - :include-source: - :context: - - plt.close('all') - arr = np.arange(100).reshape((10,10)) - fig = plt.figure(figsize=(4, 4)) - im = plt.imshow(arr, interpolation="none") - - plt.colorbar(im, use_gridspec=True) - - plt.tight_layout() - -Another option is to use AxesGrid1 toolkit to -explicitly create an axes for colorbar. - -.. plot:: - :include-source: - :context: - - plt.close('all') - arr = np.arange(100).reshape((10,10)) - fig = plt.figure(figsize=(4, 4)) - im = plt.imshow(arr, interpolation="none") - - from mpl_toolkits.axes_grid1 import make_axes_locatable - divider = make_axes_locatable(plt.gca()) - cax = divider.append_axes("right", "5%", pad="3%") - plt.colorbar(im, cax=cax) - - plt.tight_layout() diff --git a/doc/users/transforms_tutorial.rst b/doc/users/transforms_tutorial.rst deleted file mode 100644 index 57aacb1c5c93..000000000000 --- a/doc/users/transforms_tutorial.rst +++ /dev/null @@ -1,461 +0,0 @@ -.. _transforms_tutorial: - -************************** -Transformations Tutorial -************************** - -Like any graphics packages, matplotlib is built on top of a -transformation framework to easily move between coordinate systems, -the userland `data` coordinate system, the `axes` coordinate system, -the `figure` coordinate system, and the `display` coordinate system. -In 95% of your plotting, you won't need to think about this, as it -happens under the hood, but as you push the limits of custom figure -generation, it helps to have an understanding of these objects so you -can reuse the existing transformations matplotlib makes available to -you, or create your own (see :mod:`matplotlib.transforms`). The table -below summarizes the existing coordinate systems, the transformation -object you should use to work in that coordinate system, and the -description of that system. In the `Transformation Object` column, -``ax`` is a :class:`~matplotlib.axes.Axes` instance, and ``fig`` is a -:class:`~matplotlib.figure.Figure` instance. - -========== ===================== ==================================================================================== -Coordinate Transformation Object Description -========== ===================== ==================================================================================== -`data` ``ax.transData`` The userland data coordinate system, controlled by the xlim and ylim -`axes` ``ax.transAxes`` The coordinate system of the :class:`~matplotlib.axes.Axes`; (0,0) is - bottom left of the axes, and (1,1) is top right of the axes. -`figure` ``fig.transFigure`` The coordinate system of the :class:`~matplotlib.figure.Figure`; (0,0) - is bottom left of the figure, and (1,1) is top right of the figure. -`display` `None` This is the pixel coordinate system of the display; (0,0) is the bottom - left of the display, and (width, height) is the top right of the display in pixels. - Alternatively, the identity transform - (:class:`matplotlib.transforms.IdentityTransform()`) may be used instead of None. -========== ===================== ==================================================================================== - - -All of the transformation objects in the table above take inputs in -their coordinate system, and transform the input to the `display` -coordinate system. That is why the `display` coordinate system has -`None` for the `Transformation Object` column -- it already is in -display coordinates. The transformations also know how to invert -themselves, to go from `display` back to the native coordinate system. -This is particularly useful when processing events from the user -interface, which typically occur in display space, and you want to -know where the mouse click or key-press occurred in your data -coordinate system. - -.. _data-coords: - -Data coordinates -================ - -Let's start with the most commonly used coordinate, the `data` -coordinate system. Whenever you add data to the axes, matplotlib -updates the datalimits, most commonly updated with the -:meth:`~matplotlib.axes.Axes.set_xlim` and -:meth:`~matplotlib.axes.Axes.set_ylim` methods. For example, in the -figure below, the data limits stretch from 0 to 10 on the x-axis, and --1 to 1 on the y-axis. - -.. plot:: - :include-source: - - import numpy as np - import matplotlib.pyplot as plt - - x = np.arange(0, 10, 0.005) - y = np.exp(-x/2.) * np.sin(2*np.pi*x) - - fig = plt.figure() - ax = fig.add_subplot(111) - ax.plot(x, y) - ax.set_xlim(0, 10) - ax.set_ylim(-1, 1) - - plt.show() - -You can use the ``ax.transData`` instance to transform from your -`data` to your `display` coordinate system, either a single point or a -sequence of points as shown below: - -.. sourcecode:: ipython - - In [14]: type(ax.transData) - Out[14]: - - In [15]: ax.transData.transform((5, 0)) - Out[15]: array([ 335.175, 247. ]) - - In [16]: ax.transData.transform([(5, 0), (1,2)]) - Out[16]: - array([[ 335.175, 247. ], - [ 132.435, 642.2 ]]) - -You can use the :meth:`~matplotlib.transforms.Transform.inverted` -method to create a transform which will take you from display to data -coordinates: - -.. sourcecode:: ipython - - In [41]: inv = ax.transData.inverted() - - In [42]: type(inv) - Out[42]: - - In [43]: inv.transform((335.175, 247.)) - Out[43]: array([ 5., 0.]) - -If your are typing along with this tutorial, the exact values of the -display coordinates may differ if you have a different window size or -dpi setting. Likewise, in the figure below, the display labeled -points are probably not the same as in the ipython session because the -documentation figure size defaults are different. - -.. figure:: ../gallery/pyplots/images/sphx_glr_annotate_transform_001.png - :target: ../gallery/pyplots/annotate_transform.html - :align: center - :scale: 50 - - Annotate Transform - - -.. note:: - - If you run the source code in the example above in a GUI backend, - you may also find that the two arrows for the `data` and `display` - annotations do not point to exactly the same point. This is because - the display point was computed before the figure was displayed, and - the GUI backend may slightly resize the figure when it is created. - The effect is more pronounced if you resize the figure yourself. - This is one good reason why you rarely want to work in display - space, but you can connect to the ``'on_draw'`` - :class:`~matplotlib.backend_bases.Event` to update figure - coordinates on figure draws; see :ref:`event-handling-tutorial`. - -When you change the x or y limits of your axes, the data limits are -updated so the transformation yields a new display point. Note that -when we just change the ylim, only the y-display coordinate is -altered, and when we change the xlim too, both are altered. More on -this later when we talk about the -:class:`~matplotlib.transforms.Bbox`. - -.. sourcecode:: ipython - - In [54]: ax.transData.transform((5, 0)) - Out[54]: array([ 335.175, 247. ]) - - In [55]: ax.set_ylim(-1,2) - Out[55]: (-1, 2) - - In [56]: ax.transData.transform((5, 0)) - Out[56]: array([ 335.175 , 181.13333333]) - - In [57]: ax.set_xlim(10,20) - Out[57]: (10, 20) - - In [58]: ax.transData.transform((5, 0)) - Out[58]: array([-171.675 , 181.13333333]) - - - -.. _axes-coords: - -Axes coordinates -================ - -After the `data` coordinate system, `axes` is probably the second most -useful coordinate system. Here the point (0,0) is the bottom left of -your axes or subplot, (0.5, 0.5) is the center, and (1.0, 1.0) is the -top right. You can also refer to points outside the range, so (-0.1, -1.1) is to the left and above your axes. This coordinate system is -extremely useful when placing text in your axes, because you often -want a text bubble in a fixed, location, e.g., the upper left of the axes -pane, and have that location remain fixed when you pan or zoom. Here -is a simple example that creates four panels and labels them 'A', 'B', -'C', 'D' as you often see in journals. - -.. plot:: - :include-source: - - import numpy as np - import matplotlib.pyplot as plt - - fig = plt.figure() - for i, label in enumerate(('A', 'B', 'C', 'D')): - ax = fig.add_subplot(2,2,i+1) - ax.text(0.05, 0.95, label, transform=ax.transAxes, - fontsize=16, fontweight='bold', va='top') - - plt.show() - -You can also make lines or patches in the axes coordinate system, but -this is less useful in my experience than using ``ax.transAxes`` for -placing text. Nonetheless, here is a silly example which plots some -random dots in `data` space, and overlays a semi-transparent -:class:`~matplotlib.patches.Circle` centered in the middle of the axes -with a radius one quarter of the axes -- if your axes does not -preserve aspect ratio (see :meth:`~matplotlib.axes.Axes.set_aspect`), -this will look like an ellipse. Use the pan/zoom tool to move around, -or manually change the data xlim and ylim, and you will see the data -move, but the circle will remain fixed because it is not in `data` -coordinates and will always remain at the center of the axes. - -.. plot:: - :include-source: - - import numpy as np - import matplotlib.pyplot as plt - import matplotlib.patches as patches - fig = plt.figure() - ax = fig.add_subplot(111) - x, y = 10*np.random.rand(2, 1000) - ax.plot(x, y, 'go') # plot some data in data coordinates - - circ = patches.Circle((0.5, 0.5), 0.25, transform=ax.transAxes, - facecolor='yellow', alpha=0.5) - ax.add_patch(circ) - - plt.show() - -.. blended_transformations: - -Blended transformations -======================= - -Drawing in `blended` coordinate spaces which mix `axes` with `data` -coordinates is extremely useful, for example to create a horizontal -span which highlights some region of the y-data but spans across the -x-axis regardless of the data limits, pan or zoom level, etc. In fact -these blended lines and spans are so useful, we have built in -functions to make them easy to plot (see -:meth:`~matplotlib.axes.Axes.axhline`, -:meth:`~matplotlib.axes.Axes.axvline`, -:meth:`~matplotlib.axes.Axes.axhspan`, -:meth:`~matplotlib.axes.Axes.axvspan`) but for didactic purposes we -will implement the horizontal span here using a blended -transformation. This trick only works for separable transformations, -like you see in normal Cartesian coordinate systems, but not on -inseparable transformations like the -:class:`~matplotlib.projections.polar.PolarAxes.PolarTransform`. - -.. plot:: - :include-source: - - import numpy as np - import matplotlib.pyplot as plt - import matplotlib.patches as patches - import matplotlib.transforms as transforms - - fig = plt.figure() - ax = fig.add_subplot(111) - - x = np.random.randn(1000) - - ax.hist(x, 30) - ax.set_title(r'$\sigma=1 \/ \dots \/ \sigma=2$', fontsize=16) - - # the x coords of this transformation are data, and the - # y coord are axes - trans = transforms.blended_transform_factory( - ax.transData, ax.transAxes) - - # highlight the 1..2 stddev region with a span. - # We want x to be in data coordinates and y to - # span from 0..1 in axes coords - rect = patches.Rectangle((1,0), width=1, height=1, - transform=trans, color='yellow', - alpha=0.5) - - ax.add_patch(rect) - - plt.show() - -.. note:: - - The blended transformations where x is in data coords and y in axes - coordinates is so useful that we have helper methods to return the - versions mpl uses internally for drawing ticks, ticklabels, etc. - The methods are :meth:`matplotlib.axes.Axes.get_xaxis_transform` and - :meth:`matplotlib.axes.Axes.get_yaxis_transform`. So in the example - above, the call to - :meth:`~matplotlib.transforms.blended_transform_factory` can be - replaced by ``get_xaxis_transform``:: - - trans = ax.get_xaxis_transform() - -.. offset-transforms-shadow: - -Using offset transforms to create a shadow effect -================================================= - -One use of transformations is to create a new transformation that is -offset from another transformation, e.g., to place one object shifted a -bit relative to another object. Typically you want the shift to be in -some physical dimension, like points or inches rather than in data -coordinates, so that the shift effect is constant at different zoom -levels and dpi settings. - -One use for an offset is to create a shadow effect, where you draw one -object identical to the first just to the right of it, and just below -it, adjusting the zorder to make sure the shadow is drawn first and -then the object it is shadowing above it. The transforms module has a -helper transformation -:class:`~matplotlib.transforms.ScaledTranslation`. It is -instantiated with:: - - trans = ScaledTranslation(xt, yt, scale_trans) - -where `xt` and `yt` are the translation offsets, and `scale_trans` is -a transformation which scales `xt` and `yt` at transformation time -before applying the offsets. A typical use case is to use the figure -``fig.dpi_scale_trans`` transformation for the `scale_trans` argument, -to first scale `xt` and `yt` specified in points to `display` space -before doing the final offset. The dpi and inches offset is a -common-enough use case that we have a special helper function to -create it in :func:`matplotlib.transforms.offset_copy`, which returns -a new transform with an added offset. But in the example below, we'll -create the offset transform ourselves. Note the use of the plus -operator in:: - - offset = transforms.ScaledTranslation(dx, dy, - fig.dpi_scale_trans) - shadow_transform = ax.transData + offset - -showing that can chain transformations using the addition operator. -This code says: first apply the data transformation ``ax.transData`` -and then translate the data by `dx` and `dy` points. In typography, -a`point `_ is -1/72 inches, and by specifying your offsets in points, your figure -will look the same regardless of the dpi resolution it is saved in. - -.. plot:: - :include-source: - - import numpy as np - import matplotlib.pyplot as plt - import matplotlib.patches as patches - import matplotlib.transforms as transforms - - fig = plt.figure() - ax = fig.add_subplot(111) - - # make a simple sine wave - x = np.arange(0., 2., 0.01) - y = np.sin(2*np.pi*x) - line, = ax.plot(x, y, lw=3, color='blue') - - # shift the object over 2 points, and down 2 points - dx, dy = 2/72., -2/72. - offset = transforms.ScaledTranslation(dx, dy, - fig.dpi_scale_trans) - shadow_transform = ax.transData + offset - - # now plot the same data with our offset transform; - # use the zorder to make sure we are below the line - ax.plot(x, y, lw=3, color='gray', - transform=shadow_transform, - zorder=0.5*line.get_zorder()) - - ax.set_title('creating a shadow effect with an offset transform') - plt.show() - - -.. transformation-pipeline: - -The transformation pipeline -=========================== - -The ``ax.transData`` transform we have been working with in this -tutorial is a composite of three different transformations that -comprise the transformation pipeline from `data` -> `display` -coordinates. Michael Droettboom implemented the transformations -framework, taking care to provide a clean API that segregated the -nonlinear projections and scales that happen in polar and logarithmic -plots, from the linear affine transformations that happen when you pan -and zoom. There is an efficiency here, because you can pan and zoom -in your axes which affects the affine transformation, but you may not -need to compute the potentially expensive nonlinear scales or -projections on simple navigation events. It is also possible to -multiply affine transformation matrices together, and then apply them -to coordinates in one step. This is not true of all possible -transformations. - - -Here is how the ``ax.transData`` instance is defined in the basic -separable axis :class:`~matplotlib.axes.Axes` class:: - - self.transData = self.transScale + (self.transLimits + self.transAxes) - -We've been introduced to the ``transAxes`` instance above in -:ref:`axes-coords`, which maps the (0,0), (1,1) corners of the -axes or subplot bounding box to `display` space, so let's look at -these other two pieces. - -``self.transLimits`` is the transformation that takes you from -``data`` to ``axes`` coordinates; i.e., it maps your view xlim and ylim -to the unit space of the axes (and ``transAxes`` then takes that unit -space to display space). We can see this in action here - -.. sourcecode:: ipython - - In [80]: ax = subplot(111) - - In [81]: ax.set_xlim(0, 10) - Out[81]: (0, 10) - - In [82]: ax.set_ylim(-1,1) - Out[82]: (-1, 1) - - In [84]: ax.transLimits.transform((0,-1)) - Out[84]: array([ 0., 0.]) - - In [85]: ax.transLimits.transform((10,-1)) - Out[85]: array([ 1., 0.]) - - In [86]: ax.transLimits.transform((10,1)) - Out[86]: array([ 1., 1.]) - - In [87]: ax.transLimits.transform((5,0)) - Out[87]: array([ 0.5, 0.5]) - -and we can use this same inverted transformation to go from the unit -`axes` coordinates back to `data` coordinates. - -.. sourcecode:: ipython - - In [90]: inv.transform((0.25, 0.25)) - Out[90]: array([ 2.5, -0.5]) - -The final piece is the ``self.transScale`` attribute, which is -responsible for the optional non-linear scaling of the data, e.g., for -logarithmic axes. When an Axes is initially setup, this is just set to -the identity transform, since the basic matplotlib axes has linear -scale, but when you call a logarithmic scaling function like -:meth:`~matplotlib.axes.Axes.semilogx` or explicitly set the scale to -logarithmic with :meth:`~matplotlib.axes.Axes.set_xscale`, then the -``ax.transScale`` attribute is set to handle the nonlinear projection. -The scales transforms are properties of the respective ``xaxis`` and -``yaxis`` :class:`~matplotlib.axis.Axis` instances. For example, when -you call ``ax.set_xscale('log')``, the xaxis updates its scale to a -:class:`matplotlib.scale.LogScale` instance. - -For non-separable axes the PolarAxes, there is one more piece to -consider, the projection transformation. The ``transData`` -:class:`matplotlib.projections.polar.PolarAxes` is similar to that for -the typical separable matplotlib Axes, with one additional piece -``transProjection``:: - - self.transData = self.transScale + self.transProjection + \ - (self.transProjectionAffine + self.transAxes) - -``transProjection`` handles the projection from the space, -e.g., latitude and longitude for map data, or radius and theta for polar -data, to a separable Cartesian coordinate system. There are several -projection examples in the ``matplotlib.projections`` package, and the -best way to learn more is to open the source for those packages and -see how to make your own, since matplotlib supports extensible axes -and projections. Michael Droettboom has provided a nice tutorial -example of creating a hammer projection axes; see -:ref:`api-custom_projection_example`. - diff --git a/doc/users/tutorials.rst b/doc/users/tutorials.rst deleted file mode 100644 index 0675f0a4f5a3..000000000000 --- a/doc/users/tutorials.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _tutorials-index: - -=========== - Tutorials -=========== - -.. htmlonly:: - - :Release: |version| - :Date: |today| - -.. _tutorials-index-intro: - -Introductory ------------- - -.. toctree:: - :maxdepth: 2 - - pyplot_tutorial.rst - image_tutorial.rst - gridspec.rst - tight_layout_guide.rst - -.. _tutorials-index-inter: - -Intermediate ------------- -.. toctree:: - :maxdepth: 2 - - artists.rst - legend_guide.rst - -.. _tutorials-index-adv: - -Advanced --------- - -.. toctree:: - :maxdepth: 2 - - transforms_tutorial.rst - path_tutorial.rst - patheffects_guide.rst diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst index 078eef4e4912..fb03e8bf1924 100644 --- a/doc/users/whats_new.rst +++ b/doc/users/whats_new.rst @@ -287,7 +287,7 @@ Filled ``+`` and ``x`` markers New fillable *plus* and *x* markers have been added. See the :mod:`~matplotlib.markers` module and -:ref:`marker reference ` +:ref:`marker reference ` examples. `rcount` and `ccount` for `plot_surface()` diff --git a/examples/README.txt b/examples/README.txt index e7a91d293b0d..72ae0134857e 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -7,3 +7,7 @@ Gallery This gallery contains examples of the many things you can do with Matplotlib. Click on any image to see the full image and source code. + +For longer tutorials, see our `tutorials page <../tutorials/index.html>`_. +You can also find `external resources <../resources/index.html>`_ and +a `FAQ <../faq/index.html>`_ in our `user guide <../contents.html>`_. diff --git a/examples/animation/basic_example_writer_sgskip.py b/examples/animation/basic_example_writer_sgskip.py index cc08be526f98..d223471d100f 100644 --- a/examples/animation/basic_example_writer_sgskip.py +++ b/examples/animation/basic_example_writer_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ =================== Saving an animation diff --git a/examples/animation/double_pendulum_animated_sgskip.py b/examples/animation/double_pendulum_animated_sgskip.py index c24c52c5ef33..9e419f324c12 100644 --- a/examples/animation/double_pendulum_animated_sgskip.py +++ b/examples/animation/double_pendulum_animated_sgskip.py @@ -1,6 +1,4 @@ """ -.. _animation-double_pendulum_animated: - =========================== The double pendulum problem =========================== diff --git a/examples/animation/moviewriter_sgskip.py b/examples/animation/moviewriter_sgskip.py index 68fcd5b49c7e..7cd162eaac49 100644 --- a/examples/animation/moviewriter_sgskip.py +++ b/examples/animation/moviewriter_sgskip.py @@ -1,7 +1,4 @@ -# -*- noplot -*- """ -.. _animation-moviewriter: - =========== MovieWriter =========== diff --git a/examples/animation/subplots.py b/examples/animation/subplots.py index 96077a7eb56b..9af8296471a1 100644 --- a/examples/animation/subplots.py +++ b/examples/animation/subplots.py @@ -1,6 +1,4 @@ """ -.. _animation-subplots: - ================= Animated subplots ================= diff --git a/examples/api/agg_oo_sgskip.py b/examples/api/agg_oo_sgskip.py index 6a3aee202b70..502f95cf835a 100644 --- a/examples/api/agg_oo_sgskip.py +++ b/examples/api/agg_oo_sgskip.py @@ -1,7 +1,4 @@ -# -*- noplot -*- """ -.. _api-agg_oo: - ============================= The object-oriented interface ============================= diff --git a/examples/api/custom_projection_example.py b/examples/api/custom_projection_example.py index 98fb2e7294c3..1747027146ba 100644 --- a/examples/api/custom_projection_example.py +++ b/examples/api/custom_projection_example.py @@ -1,6 +1,4 @@ """ -.. _api-custom_projection_example: - ================= Custom projection ================= diff --git a/examples/api/font_family_rc_sgskip.py b/examples/api/font_family_rc_sgskip.py index e06a4049f11b..807f3515b346 100644 --- a/examples/api/font_family_rc_sgskip.py +++ b/examples/api/font_family_rc_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ =========================== Configuring the font family diff --git a/examples/api/font_file_sgskip.py b/examples/api/font_file_sgskip.py index 367a7484ba9f..f72c039d5c54 100644 --- a/examples/api/font_file_sgskip.py +++ b/examples/api/font_file_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ =================================== Using a ttf font file in matplotlib diff --git a/examples/api/legend.py b/examples/api/legend.py index 4f518efa0850..de50130d2224 100644 --- a/examples/api/legend.py +++ b/examples/api/legend.py @@ -1,6 +1,4 @@ """ -.. _api-legend: - =============================== Legend using pre-defined labels =============================== diff --git a/examples/api/sankey_basics.py b/examples/api/sankey_basics.py index fe1c78e9f662..b582fcfeee8a 100644 --- a/examples/api/sankey_basics.py +++ b/examples/api/sankey_basics.py @@ -1,6 +1,4 @@ """ -.. _api-sankey_basics: - ================ The Sankey class ================ diff --git a/examples/api/sankey_links.py b/examples/api/sankey_links.py index 45c2defbfdb9..b8de4744edb3 100644 --- a/examples/api/sankey_links.py +++ b/examples/api/sankey_links.py @@ -1,6 +1,4 @@ """ -.. _api-sankey_links: - ====================================== Long chain of connections using Sankey ====================================== diff --git a/examples/api/sankey_rankine.py b/examples/api/sankey_rankine.py index d08265e4ddbc..59f1174184a6 100644 --- a/examples/api/sankey_rankine.py +++ b/examples/api/sankey_rankine.py @@ -1,6 +1,4 @@ """ -.. _api-sankey_rankine: - =================== Rankine power cycle =================== diff --git a/examples/api/two_scales.py b/examples/api/two_scales.py index 0d20cab0fcc3..ca5b4eddfbaa 100644 --- a/examples/api/two_scales.py +++ b/examples/api/two_scales.py @@ -1,6 +1,4 @@ """ -.. _api-two_scales: - =========================== Plots with different scales =========================== diff --git a/examples/color/README.txt b/examples/color/README.txt index 7bd143064172..4bcdb526f4d4 100644 --- a/examples/color/README.txt +++ b/examples/color/README.txt @@ -2,3 +2,7 @@ Color ===== + +For more in-depth information about the colormaps available in matplotlib +as well as a description of their properties, +see the :ref:`colormaps tutorial `. diff --git a/examples/color/colormaps.py b/examples/color/colormaps.py deleted file mode 100644 index f6462d2e9d24..000000000000 --- a/examples/color/colormaps.py +++ /dev/null @@ -1,31 +0,0 @@ -""" -================= -List of Colormaps -================= - -""" - -# Have colormaps separated into categories: -# http://matplotlib.org/examples/color/colormaps_reference.html - -cmaps = [('Perceptually Uniform Sequential', [ - 'viridis', 'plasma', 'inferno', 'magma']), - ('Sequential', [ - 'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds', - 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', - 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn']), - ('Sequential (2)', [ - 'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink', - 'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia', - 'hot', 'afmhot', 'gist_heat', 'copper']), - ('Diverging', [ - 'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', - 'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic']), - ('Qualitative', [ - 'Pastel1', 'Pastel2', 'Paired', 'Accent', - 'Dark2', 'Set1', 'Set2', 'Set3', - 'tab10', 'tab20', 'tab20b', 'tab20c']), - ('Miscellaneous', [ - 'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern', - 'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg', 'hsv', - 'gist_rainbow', 'rainbow', 'jet', 'nipy_spectral', 'gist_ncar'])] diff --git a/examples/color/colormaps_reference.py b/examples/color/colormaps_reference.py deleted file mode 100644 index 876b9822cd81..000000000000 --- a/examples/color/colormaps_reference.py +++ /dev/null @@ -1,95 +0,0 @@ -""" -.. _color-colormaps_reference: - -================== -Colormap reference -================== - -Reference for colormaps included with Matplotlib. - -This reference example shows all colormaps included with Matplotlib. Note that -any colormap listed here can be reversed by appending "_r" (e.g., "pink_r"). -These colormaps are divided into the following categories: - -Sequential: - These colormaps are approximately monochromatic colormaps varying smoothly - between two color tones---usually from low saturation (e.g. white) to high - saturation (e.g. a bright blue). Sequential colormaps are ideal for - representing most scientific data since they show a clear progression from - low-to-high values. - -Diverging: - These colormaps have a median value (usually light in color) and vary - smoothly to two different color tones at high and low values. Diverging - colormaps are ideal when your data has a median value that is significant - (e.g. 0, such that positive and negative values are represented by - different colors of the colormap). - -Qualitative: - These colormaps vary rapidly in color. Qualitative colormaps are useful for - choosing a set of discrete colors. For example:: - - color_list = plt.cm.Set3(np.linspace(0, 1, 12)) - - gives a list of RGB colors that are good for plotting a series of lines on - a dark background. - -Miscellaneous: - Colormaps that don't fit into the categories above. - -""" -import numpy as np -import matplotlib.pyplot as plt - - -# Have colormaps separated into categories: -# http://matplotlib.org/examples/color/colormaps_reference.html -cmaps = [('Perceptually Uniform Sequential', [ - 'viridis', 'plasma', 'inferno', 'magma']), - ('Sequential', [ - 'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds', - 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', - 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn']), - ('Sequential (2)', [ - 'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink', - 'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia', - 'hot', 'afmhot', 'gist_heat', 'copper']), - ('Diverging', [ - 'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', - 'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic']), - ('Qualitative', [ - 'Pastel1', 'Pastel2', 'Paired', 'Accent', - 'Dark2', 'Set1', 'Set2', 'Set3', - 'tab10', 'tab20', 'tab20b', 'tab20c']), - ('Miscellaneous', [ - 'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern', - 'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg', 'hsv', - 'gist_rainbow', 'rainbow', 'jet', 'nipy_spectral', 'gist_ncar'])] - - -nrows = max(len(cmap_list) for cmap_category, cmap_list in cmaps) -gradient = np.linspace(0, 1, 256) -gradient = np.vstack((gradient, gradient)) - - -def plot_color_gradients(cmap_category, cmap_list, nrows): - fig, axes = plt.subplots(nrows=nrows) - fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99) - axes[0].set_title(cmap_category + ' colormaps', fontsize=14) - - for ax, name in zip(axes, cmap_list): - ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(name)) - pos = list(ax.get_position().bounds) - x_text = pos[0] - 0.01 - y_text = pos[1] + pos[3]/2. - fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10) - - # Turn off *all* ticks & spines, not just the ones with colormaps. - for ax in axes: - ax.set_axis_off() - - -for cmap_category, cmap_list in cmaps: - plot_color_gradients(cmap_category, cmap_list, nrows) - -plt.show() diff --git a/examples/color/grayscale.py b/examples/color/grayscale.py deleted file mode 100644 index 030134197f23..000000000000 --- a/examples/color/grayscale.py +++ /dev/null @@ -1,58 +0,0 @@ -''' -================================== -Grayscale version of the colormaps -================================== - -Show what Matplotlib colormaps look like in grayscale. -Uses lightness L* as a proxy for grayscale value. -''' - -import numpy as np -import matplotlib as mpl -import matplotlib.pyplot as plt -from matplotlib import cm -from colorspacious import cspace_converter -from colormaps import cmaps # the colormaps, grouped by category - -mpl.rcParams.update({'font.size': 14}) - -# Indices to step through colormap. -x = np.linspace(0.0, 1.0, 100) - -gradient = np.linspace(0, 1, 256) -gradient = np.vstack((gradient, gradient)) - - -def plot_color_gradients(cmap_category, cmap_list): - fig, axes = plt.subplots(nrows=len(cmap_list), ncols=2) - fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99, - wspace=0.05) - fig.suptitle(cmap_category + ' colormaps', fontsize=14, y=1.0, x=0.6) - - for ax, name in zip(axes, cmap_list): - - # Get RGB values for colormap. - rgb = cm.get_cmap(plt.get_cmap(name))(x)[np.newaxis,:,:3] - - # Get colormap in CAM02-UCS colorspace. We want the lightness. - lab = cspace_converter("sRGB1", "CAM02-UCS")(rgb) - L = lab[0,:,0] - L = np.float32(np.vstack((L, L, L))) - - ax[0].imshow(gradient, aspect='auto', cmap=plt.get_cmap(name)) - ax[1].imshow(L, aspect='auto', cmap='binary_r', vmin=0., vmax=100.) - pos = list(ax[0].get_position().bounds) - x_text = pos[0] - 0.01 - y_text = pos[1] + pos[3]/2. - fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10) - - # Turn off *all* ticks & spines, not just the ones with colormaps. - for ax in axes.flat: - ax.set_axis_off() - - plt.show() - - -for cmap_category, cmap_list in cmaps: - - plot_color_gradients(cmap_category, cmap_list) diff --git a/examples/color/lightness.py b/examples/color/lightness.py deleted file mode 100644 index 63908861deb6..000000000000 --- a/examples/color/lightness.py +++ /dev/null @@ -1,100 +0,0 @@ -''' -========================== -Lightness of the colormaps -========================== - -For each colormap, plot the lightness parameter L* from CIELAB colorspace -along the y axis vs index through the colormap. Colormaps are examined in -categories as in the original matplotlib gallery of colormaps. -''' - -import numpy as np -import matplotlib as mpl -import matplotlib.pyplot as plt -from matplotlib import cm -from colorspacious import cspace_converter -from colormaps import cmaps # the colormaps, grouped by category - -mpl.rcParams.update({'font.size': 12}) - -# Number of colormap per subplot for particular cmap categories -_DSUBS = {'Perceptually Uniform Sequential': 4, 'Sequential': 6, - 'Sequential (2)': 6, 'Diverging': 6, 'Qualitative': 4, - 'Miscellaneous': 6} - -# Spacing between the colormaps of a subplot -_DC = {'Perceptually Uniform Sequential': 1.4, 'Sequential': 0.7, - 'Sequential (2)': 1.4, 'Diverging': 1.4, 'Qualitative': 1.4, - 'Miscellaneous': 1.4} - -# Indices to step through colormap -x = np.linspace(0.0, 1.0, 100) - -# Do plot -for cmap_category, cmap_list in cmaps: - - # Do subplots so that colormaps have enough space. - # Default is 6 colormaps per subplot. - dsub = _DSUBS.get(cmap_category, 6) - nsubplots = int(np.ceil(len(cmap_list) / float(dsub))) - - # squeeze=False to handle similarly the case of a single subplot - fig, axes = plt.subplots(nrows=nsubplots, squeeze=False, - figsize=(7, 2.6*nsubplots)) - - for i, ax in enumerate(axes.flat): - - locs = [] # locations for text labels - - for j, cmap in enumerate(cmap_list[i*dsub:(i+1)*dsub]): - - # Get RGB values for colormap and convert the colormap in - # CAM02-UCS colorspace. lab[0, :, 0] is the lightness. - rgb = cm.get_cmap(cmap)(x)[np.newaxis, :, :3] - lab = cspace_converter("sRGB1", "CAM02-UCS")(rgb) - - # Plot colormap L values. Do separately for each category - # so each plot can be pretty. To make scatter markers change - # color along plot: - # http://stackoverflow.com/questions/8202605/matplotlib-scatterplot-colour-as-a-function-of-a-third-variable - - if cmap_category == 'Sequential': - # These colormaps all start at high lightness but we want them - # reversed to look nice in the plot, so reverse the order. - y_ = lab[0, ::-1, 0] - c_ = x[::-1] - else: - y_ = lab[0, :, 0] - c_ = x - - dc = _DC.get(cmap_category, 1.4) # cmaps horizontal spacing - ax.scatter(x + j*dc, y_, c=c_, cmap=cmap, s=300, linewidths=0.0) - - # Store locations for colormap labels - if cmap_category in ('Perceptually Uniform Sequential', - 'Sequential'): - locs.append(x[-1] + j*dc) - elif cmap_category in ('Diverging', 'Qualitative', - 'Miscellaneous', 'Sequential (2)'): - locs.append(x[int(x.size/2.)] + j*dc) - - # Set up the axis limits: - # * the 1st subplot is used as a reference for the x-axis limits - # * lightness values goes from 0 to 100 (y-axis limits) - ax.set_xlim(axes[0, 0].get_xlim()) - ax.set_ylim(0.0, 100.0) - - # Set up labels for colormaps - ax.xaxis.set_ticks_position('top') - ticker = mpl.ticker.FixedLocator(locs) - ax.xaxis.set_major_locator(ticker) - formatter = mpl.ticker.FixedFormatter(cmap_list[i*dsub:(i+1)*dsub]) - ax.xaxis.set_major_formatter(formatter) - ax.xaxis.set_tick_params(rotation=50) - - ax.set_xlabel(cmap_category + ' colormaps', fontsize=14) - fig.text(0.0, 0.55, 'Lightness $L^*$', fontsize=12, - transform=fig.transFigure, rotation=90) - - fig.tight_layout(h_pad=0.0, pad=1.5) - plt.show() diff --git a/examples/lines_bars_and_markers/marker_reference.py b/examples/lines_bars_and_markers/marker_reference.py index 4c00ef16a37e..7927bbe612a6 100644 --- a/examples/lines_bars_and_markers/marker_reference.py +++ b/examples/lines_bars_and_markers/marker_reference.py @@ -1,6 +1,4 @@ """ -.. _lines_bars_and_markers-marker_reference: - ================================ Filled and unfilled-marker types ================================ diff --git a/examples/lines_bars_and_markers/scatter_with_legend.py b/examples/lines_bars_and_markers/scatter_with_legend.py index 5145184f580c..1327f5cd170b 100644 --- a/examples/lines_bars_and_markers/scatter_with_legend.py +++ b/examples/lines_bars_and_markers/scatter_with_legend.py @@ -1,6 +1,4 @@ """ -.. _lines_bars_and_markers-scatter_with_legend: - =========================== Scatter plots with a legend =========================== diff --git a/examples/misc/image_thumbnail_sgskip.py b/examples/misc/image_thumbnail_sgskip.py index 5b25ea18d738..c9d02eb82303 100644 --- a/examples/misc/image_thumbnail_sgskip.py +++ b/examples/misc/image_thumbnail_sgskip.py @@ -1,7 +1,4 @@ -# -*- noplot -*- """ -.. _misc-image_thumbnail: - =============== Image Thumbnail =============== diff --git a/examples/misc/multiprocess_sgskip.py b/examples/misc/multiprocess_sgskip.py index a640954cf3ed..eace2e05fd88 100644 --- a/examples/misc/multiprocess_sgskip.py +++ b/examples/misc/multiprocess_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ ============ Multiprocess diff --git a/examples/misc/rc_traits_sgskip.py b/examples/misc/rc_traits_sgskip.py index 7ba0b91a50d6..89fef24b753a 100644 --- a/examples/misc/rc_traits_sgskip.py +++ b/examples/misc/rc_traits_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ ========= Rc Traits diff --git a/examples/pylab_examples/animation_demo.py b/examples/pylab_examples/animation_demo.py index a59009910cd3..76f7b9804d3e 100644 --- a/examples/pylab_examples/animation_demo.py +++ b/examples/pylab_examples/animation_demo.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-animation_demo: - ============== Animation Demo ============== diff --git a/examples/pylab_examples/annotation_demo.py b/examples/pylab_examples/annotation_demo.py index 9696a575daa4..b514626c64e0 100644 --- a/examples/pylab_examples/annotation_demo.py +++ b/examples/pylab_examples/annotation_demo.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-annotation_demo: - =============== Annotation Demo =============== diff --git a/examples/pylab_examples/annotation_demo3.py b/examples/pylab_examples/annotation_demo3.py index 1ef39710d89c..6baa8e7f8609 100644 --- a/examples/pylab_examples/annotation_demo3.py +++ b/examples/pylab_examples/annotation_demo3.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-annotation_demo3: - ================ Annotation Demo3 ================ diff --git a/examples/pylab_examples/axes_demo.py b/examples/pylab_examples/axes_demo.py index fb7aa0b3a064..e57496522f4d 100644 --- a/examples/pylab_examples/axes_demo.py +++ b/examples/pylab_examples/axes_demo.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-axes_demo: - ========= Axes Demo ========= diff --git a/examples/pylab_examples/axhspan_demo.py b/examples/pylab_examples/axhspan_demo.py index 4cfe6249a564..c9cbf3d81a37 100644 --- a/examples/pylab_examples/axhspan_demo.py +++ b/examples/pylab_examples/axhspan_demo.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-axhspan_demo: - ============ Axhspan Demo ============ diff --git a/examples/pylab_examples/colours_sgskip.py b/examples/pylab_examples/colours_sgskip.py index 6ea0e268ac0a..25636c24e7fa 100644 --- a/examples/pylab_examples/colours_sgskip.py +++ b/examples/pylab_examples/colours_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ ======= Colours diff --git a/examples/pylab_examples/contourf_hatching.py b/examples/pylab_examples/contourf_hatching.py index 2fca24e8e492..e28a64a886bd 100644 --- a/examples/pylab_examples/contourf_hatching.py +++ b/examples/pylab_examples/contourf_hatching.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-contourf_hatching: - ================= Contourf Hatching ================= diff --git a/examples/pylab_examples/cursor_demo_sgskip.py b/examples/pylab_examples/cursor_demo_sgskip.py index 18bcdf2b08d0..aaa551aeb647 100644 --- a/examples/pylab_examples/cursor_demo_sgskip.py +++ b/examples/pylab_examples/cursor_demo_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ =========== Cursor Demo diff --git a/examples/pylab_examples/figlegend_demo.py b/examples/pylab_examples/figlegend_demo.py index 39e7fd3d1481..ddb52d550e81 100644 --- a/examples/pylab_examples/figlegend_demo.py +++ b/examples/pylab_examples/figlegend_demo.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-figlegend_demo: - ================== Figure legend demo ================== diff --git a/examples/pylab_examples/font_table_ttf_sgskip.py b/examples/pylab_examples/font_table_ttf_sgskip.py index eeb85016f7bc..9a2153d01d4c 100644 --- a/examples/pylab_examples/font_table_ttf_sgskip.py +++ b/examples/pylab_examples/font_table_ttf_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ ============== Font Table TTF diff --git a/examples/pylab_examples/ginput_demo_sgskip.py b/examples/pylab_examples/ginput_demo_sgskip.py index 710000f910a9..77227032b16a 100644 --- a/examples/pylab_examples/ginput_demo_sgskip.py +++ b/examples/pylab_examples/ginput_demo_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ =========== Ginput Demo diff --git a/examples/pylab_examples/ginput_manual_clabel_sgskip.py b/examples/pylab_examples/ginput_manual_clabel_sgskip.py index 00e77287a18d..fabd6d5e7dd0 100644 --- a/examples/pylab_examples/ginput_manual_clabel_sgskip.py +++ b/examples/pylab_examples/ginput_manual_clabel_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ ===================== Interactive functions diff --git a/examples/pylab_examples/hyperlinks_sgskip.py b/examples/pylab_examples/hyperlinks_sgskip.py index 0fef971cb4b8..ab8c29ded55f 100644 --- a/examples/pylab_examples/hyperlinks_sgskip.py +++ b/examples/pylab_examples/hyperlinks_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ ========== Hyperlinks diff --git a/examples/pylab_examples/major_minor_demo1.py b/examples/pylab_examples/major_minor_demo1.py index d5637d4e3efb..9b216626a4fe 100644 --- a/examples/pylab_examples/major_minor_demo1.py +++ b/examples/pylab_examples/major_minor_demo1.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-major_minor_demo1: - ================= Major Minor Demo1 ================= diff --git a/examples/pylab_examples/movie_demo_sgskip.py b/examples/pylab_examples/movie_demo_sgskip.py index da7fac339395..32424f9a0898 100644 --- a/examples/pylab_examples/movie_demo_sgskip.py +++ b/examples/pylab_examples/movie_demo_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ ========== Movie Demo diff --git a/examples/pylab_examples/print_stdout_sgskip.py b/examples/pylab_examples/print_stdout_sgskip.py index 25c63c619c6b..da86a2c3cb16 100644 --- a/examples/pylab_examples/print_stdout_sgskip.py +++ b/examples/pylab_examples/print_stdout_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ ============ Print Stdout diff --git a/examples/pylab_examples/psd_demo2.py b/examples/pylab_examples/psd_demo2.py index 7eed88a69f4a..33d3c1ba0513 100644 --- a/examples/pylab_examples/psd_demo2.py +++ b/examples/pylab_examples/psd_demo2.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-psd_demo2: - ========= Psd Demo2 ========= diff --git a/examples/pylab_examples/psd_demo3.py b/examples/pylab_examples/psd_demo3.py index 22190517fb11..68506b3a23bf 100644 --- a/examples/pylab_examples/psd_demo3.py +++ b/examples/pylab_examples/psd_demo3.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-psd_demo3: - ========= Psd Demo3 ========= diff --git a/examples/pylab_examples/scatter_symbol.py b/examples/pylab_examples/scatter_symbol.py index 8d24da24d451..c9caaeb94339 100644 --- a/examples/pylab_examples/scatter_symbol.py +++ b/examples/pylab_examples/scatter_symbol.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-scatter_symbol: - ============== Scatter Symbol ============== diff --git a/examples/pylab_examples/spine_placement_demo.py b/examples/pylab_examples/spine_placement_demo.py index 05ca07912898..3dc6b1f281d9 100644 --- a/examples/pylab_examples/spine_placement_demo.py +++ b/examples/pylab_examples/spine_placement_demo.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-spine_placement_demo: - ==================== Spine Placement Demo ==================== diff --git a/examples/pylab_examples/subplot_demo.py b/examples/pylab_examples/subplot_demo.py index 7fc0aa5eaf3d..0f77d69e2a4e 100644 --- a/examples/pylab_examples/subplot_demo.py +++ b/examples/pylab_examples/subplot_demo.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-subplots_demo: - ============ Subplot Demo ============ diff --git a/examples/pylab_examples/webapp_demo_sgskip.py b/examples/pylab_examples/webapp_demo_sgskip.py index 345a1115e27f..35cf83a78bf3 100644 --- a/examples/pylab_examples/webapp_demo_sgskip.py +++ b/examples/pylab_examples/webapp_demo_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ =========== Webapp Demo diff --git a/examples/pylab_examples/zorder_demo.py b/examples/pylab_examples/zorder_demo.py index 0bdce5a23818..c552a4a56fa2 100644 --- a/examples/pylab_examples/zorder_demo.py +++ b/examples/pylab_examples/zorder_demo.py @@ -1,6 +1,4 @@ """ -.. _pylab_examples-zorder_demo: - =========== Zorder Demo =========== diff --git a/examples/recipes/README.txt b/examples/recipes/README.txt new file mode 100644 index 000000000000..63a3ca0d4e56 --- /dev/null +++ b/examples/recipes/README.txt @@ -0,0 +1,8 @@ +.. _recipes: + +Our Favorite Recipes +==================== + +Here is a collection of short tutorials, examples and code snippets +that illustrate some of the useful idioms and tricks to make snazzier +figures and overcome some matplotlib warts. diff --git a/examples/recipes/common_date_problems.py b/examples/recipes/common_date_problems.py new file mode 100644 index 000000000000..cb9bde619195 --- /dev/null +++ b/examples/recipes/common_date_problems.py @@ -0,0 +1,90 @@ +""" +Fixing common date annoyances +============================= + +Matplotlib allows you to natively plots python datetime instances, and +for the most part does a good job picking tick locations and string +formats. There are a couple of things it does not handle so +gracefully, and here are some tricks to help you work around them. +We'll load up some sample date data which contains datetime.date +objects in a numpy record array:: + + In [63]: datafile = cbook.get_sample_data('goog.npz') + + In [64]: r = np.load(datafile)['price_data'].view(np.recarray) + + In [65]: r.dtype + Out[65]: dtype([('date', '] + +you will see that the x tick labels are all squashed together. +""" +import matplotlib.cbook as cbook +import matplotlib.dates as mdates +import numpy as np +import matplotlib.pyplot as plt + +with cbook.get_sample_data('goog.npz') as datafile: + r = np.load(datafile)['price_data'].view(np.recarray) + +# Matplotlib prefers datetime instead of np.datetime64. +date = r.date.astype('O') +plt.figure() +plt.plot(date, r.close) +plt.title('Default date handling can cause overlapping labels') + +############################################################################### +# Another annoyance is that if you hover the mouse over the window and +# look in the lower right corner of the matplotlib toolbar +# (:ref:`navigation-toolbar`) at the x and y coordinates, you see that +# the x locations are formatted the same way the tick labels are, e.g., +# "Dec 2004". +# +# What we'd like is for the location in the toolbar to have +# a higher degree of precision, e.g., giving us the exact date out mouse is +# hovering over. To fix the first problem, we can use +# :func:`matplotlib.figure.Figure.autofmt_xdate` and to fix the second +# problem we can use the ``ax.fmt_xdata`` attribute which can be set to +# any function that takes a scalar and returns a string. matplotlib has +# a number of date formatters built in, so we'll use one of those. + +fig, ax = plt.subplots() +ax.plot(date, r.close) + +# rotate and align the tick labels so they look better +fig.autofmt_xdate() + +# use a more precise date string for the x axis locations in the +# toolbar +ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d') +ax.set_title('fig.autofmt_xdate fixes the labels') + +############################################################################### +# Now when you hover your mouse over the plotted data, you'll see date +# format strings like 2004-12-01 in the toolbar. diff --git a/examples/recipes/create_subplots.py b/examples/recipes/create_subplots.py new file mode 100644 index 000000000000..1a177d3c9cbf --- /dev/null +++ b/examples/recipes/create_subplots.py @@ -0,0 +1,39 @@ +""" +Easily creating subplots +======================== + +In early versions of matplotlib, if you wanted to use the pythonic API +and create a figure instance and from that create a grid of subplots, +possibly with shared axes, it involved a fair amount of boilerplate +code. e.g. +""" + +import matplotlib.pyplot as plt +import numpy as np + +x = np.random.randn(50) + +# old style +fig = plt.figure() +ax1 = fig.add_subplot(221) +ax2 = fig.add_subplot(222, sharex=ax1, sharey=ax1) +ax3 = fig.add_subplot(223, sharex=ax1, sharey=ax1) +ax3 = fig.add_subplot(224, sharex=ax1, sharey=ax1) + +############################################################################### +# Fernando Perez has provided a nice top level method to create in +# :func:`~matplotlib.pyplots.subplots` (note the "s" at the end) +# everything at once, and turn on x and y sharing for the whole bunch. +# You can either unpack the axes individually:: + +# new style method 1; unpack the axes +fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, sharex=True, sharey=True) +ax1.plot(x) + +############################################################################### +# or get them back as a numrows x numcolumns object array which supports +# numpy indexing + +# new style method 2; use an axes array +fig, axs = plt.subplots(2, 2, sharex=True, sharey=True) +axs[0, 0].plot(x) diff --git a/examples/recipes/fill_between_alpha.py b/examples/recipes/fill_between_alpha.py new file mode 100644 index 000000000000..eb36d7b32a29 --- /dev/null +++ b/examples/recipes/fill_between_alpha.py @@ -0,0 +1,136 @@ +""" +Fill Between and Alpha +====================== + +The :meth:`~matplotlib.axes.Axes.fill_between` function generates a +shaded region between a min and max boundary that is useful for +illustrating ranges. It has a very handy ``where`` argument to +combine filling with logical ranges, e.g., to just fill in a curve over +some threshold value. + +At its most basic level, ``fill_between`` can be use to enhance a +graphs visual appearance. Let's compare two graphs of a financial +times with a simple line plot on the left and a filled line on the +right. +""" + +import matplotlib.pyplot as plt +import numpy as np +import matplotlib.cbook as cbook + +# load up some sample financial data +with cbook.get_sample_data('goog.npz') as datafile: + r = np.load(datafile)['price_data'].view(np.recarray) +# Matplotlib prefers datetime instead of np.datetime64. +date = r.date.astype('O') +# create two subplots with the shared x and y axes +fig, (ax1, ax2) = plt.subplots(1, 2, sharex=True, sharey=True) + +pricemin = r.close.min() + +ax1.plot(date, r.close, lw=2) +ax2.fill_between(date, pricemin, r.close, facecolor='blue', alpha=0.5) + +for ax in ax1, ax2: + ax.grid(True) + +ax1.set_ylabel('price') +for label in ax2.get_yticklabels(): + label.set_visible(False) + +fig.suptitle('Google (GOOG) daily closing price') +fig.autofmt_xdate() + +############################################################################### +# The alpha channel is not necessary here, but it can be used to soften +# colors for more visually appealing plots. In other examples, as we'll +# see below, the alpha channel is functionally useful as the shaded +# regions can overlap and alpha allows you to see both. Note that the +# postscript format does not support alpha (this is a postscript +# limitation, not a matplotlib limitation), so when using alpha save +# your figures in PNG, PDF or SVG. +# +# Our next example computes two populations of random walkers with a +# different mean and standard deviation of the normal distributions from +# which the steps are drawn. We use shared regions to plot +/- one +# standard deviation of the mean position of the population. Here the +# alpha channel is useful, not just aesthetic. + +Nsteps, Nwalkers = 100, 250 +t = np.arange(Nsteps) + +# an (Nsteps x Nwalkers) array of random walk steps +S1 = 0.002 + 0.01*np.random.randn(Nsteps, Nwalkers) +S2 = 0.004 + 0.02*np.random.randn(Nsteps, Nwalkers) + +# an (Nsteps x Nwalkers) array of random walker positions +X1 = S1.cumsum(axis=0) +X2 = S2.cumsum(axis=0) + + +# Nsteps length arrays empirical means and standard deviations of both +# populations over time +mu1 = X1.mean(axis=1) +sigma1 = X1.std(axis=1) +mu2 = X2.mean(axis=1) +sigma2 = X2.std(axis=1) + +# plot it! +fig, ax = plt.subplots(1) +ax.plot(t, mu1, lw=2, label='mean population 1', color='blue') +ax.plot(t, mu2, lw=2, label='mean population 2', color='yellow') +ax.fill_between(t, mu1+sigma1, mu1-sigma1, facecolor='blue', alpha=0.5) +ax.fill_between(t, mu2+sigma2, mu2-sigma2, facecolor='yellow', alpha=0.5) +ax.set_title('random walkers empirical $\mu$ and $\pm \sigma$ interval') +ax.legend(loc='upper left') +ax.set_xlabel('num steps') +ax.set_ylabel('position') +ax.grid() + +############################################################################### +# The ``where`` keyword argument is very handy for highlighting certain +# regions of the graph. ``where`` takes a boolean mask the same length +# as the x, ymin and ymax arguments, and only fills in the region where +# the boolean mask is True. In the example below, we simulate a single +# random walker and compute the analytic mean and standard deviation of +# the population positions. The population mean is shown as the black +# dashed line, and the plus/minus one sigma deviation from the mean is +# shown as the yellow filled region. We use the where mask +# ``X > upper_bound`` to find the region where the walker is above the one +# sigma boundary, and shade that region blue. + +Nsteps = 500 +t = np.arange(Nsteps) + +mu = 0.002 +sigma = 0.01 + +# the steps and position +S = mu + sigma*np.random.randn(Nsteps) +X = S.cumsum() + +# the 1 sigma upper and lower analytic population bounds +lower_bound = mu*t - sigma*np.sqrt(t) +upper_bound = mu*t + sigma*np.sqrt(t) + +fig, ax = plt.subplots(1) +ax.plot(t, X, lw=2, label='walker position', color='blue') +ax.plot(t, mu*t, lw=1, label='population mean', color='black', ls='--') +ax.fill_between(t, lower_bound, upper_bound, facecolor='yellow', alpha=0.5, + label='1 sigma range') +ax.legend(loc='upper left') + +# here we use the where argument to only fill the region where the +# walker is above the population 1 sigma boundary +ax.fill_between(t, upper_bound, X, where=X > upper_bound, facecolor='blue', + alpha=0.5) +ax.set_xlabel('num steps') +ax.set_ylabel('position') +ax.grid() + +############################################################################### +# Another handy use of filled regions is to highlight horizontal or +# vertical spans of an axes -- for that matplotlib has some helper +# functions :meth:`~matplotlib.axes.Axes.axhspan` and +# :meth:`~matplotlib.axes.Axes.axvspan` and example +# :ref:`sphx_glr_gallery_pylab_examples_axhspan_demo.py`. diff --git a/examples/recipes/placing_text_boxes.py b/examples/recipes/placing_text_boxes.py new file mode 100644 index 000000000000..b8184f729985 --- /dev/null +++ b/examples/recipes/placing_text_boxes.py @@ -0,0 +1,31 @@ +""" +Placing text boxes +================== + +When decorating axes with text boxes, two useful tricks are to place +the text in axes coordinates (see :ref:`sphx_glr_tutorials_03_advanced_transforms_tutorial.py`), so the +text doesn't move around with changes in x or y limits. You can also +use the ``bbox`` property of text to surround the text with a +:class:`~matplotlib.patches.Patch` instance -- the ``bbox`` keyword +argument takes a dictionary with keys that are Patch properties. +""" + +import numpy as np +import matplotlib.pyplot as plt + +np.random.seed(1234) + +fig, ax = plt.subplots() +x = 30*np.random.randn(10000) +mu = x.mean() +median = np.median(x) +sigma = x.std() +textstr = '$\mu=%.2f$\n$\mathrm{median}=%.2f$\n$\sigma=%.2f$' % (mu, median, sigma) + +ax.hist(x, 50) +# these are matplotlib.patch.Patch properties +props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) + +# place a text box in upper left in axes coords +ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=14, + verticalalignment='top', bbox=props) diff --git a/examples/recipes/share_axis_lims_views.py b/examples/recipes/share_axis_lims_views.py new file mode 100644 index 000000000000..b80393afb848 --- /dev/null +++ b/examples/recipes/share_axis_lims_views.py @@ -0,0 +1,25 @@ +""" +Sharing axis limits and views +============================= + +It's common to make two or more plots which share an axis, e.g., two +subplots with time as a common axis. When you pan and zoom around on +one, you want the other to move around with you. To facilitate this, +matplotlib Axes support a ``sharex`` and ``sharey`` attribute. When +you create a :func:`~matplotlib.pyplot.subplot` or +:func:`~matplotlib.pyplot.axes` instance, you can pass in a keyword +indicating what axes you want to share with +""" + +import numpy as np +import matplotlib.pyplot as plt + +t = np.arange(0, 10, 0.01) + +ax1 = plt.subplot(211) + +ax1.plot(t, np.sin(2*np.pi*t)) + +ax2 = plt.subplot(212, sharex=ax1) + +ax2.plot(t, np.sin(4*np.pi*t)) diff --git a/examples/recipes/transparent_legends.py b/examples/recipes/transparent_legends.py new file mode 100644 index 000000000000..0219d5fe5f48 --- /dev/null +++ b/examples/recipes/transparent_legends.py @@ -0,0 +1,31 @@ +""" +Transparent, fancy legends +========================== + +Sometimes you know what your data looks like before you plot it, and +may know for instance that there won't be much data in the upper right +hand corner. Then you can safely create a legend that doesn't overlay +your data: + + ax.legend(loc='upper right') + +Other times you don't know where your data is, and loc='best' will try +and place the legend:: + + ax.legend(loc='best') + +but still, your legend may overlap your data, and in these cases it's +nice to make the legend frame transparent. +""" + +import matplotlib.pyplot as plt +import numpy as np + +np.random.seed(1234) +fig, ax = plt.subplots(1) +ax.plot(np.random.randn(300), 'o-', label='normal distribution') +ax.plot(np.random.rand(300), 's-', label='uniform distribution') +ax.set_ylim(-3, 3) + +ax.legend(loc='best', fancybox=True, framealpha=0.5) +ax.set_title('fancy, transparent legends') diff --git a/examples/statistics/boxplot.py b/examples/statistics/boxplot.py index 3f34a0beb4ca..356b8d5ab46f 100644 --- a/examples/statistics/boxplot.py +++ b/examples/statistics/boxplot.py @@ -1,6 +1,4 @@ """ -.. _statistics-boxplot: - ========================================= Demo of artist customization in box plots ========================================= diff --git a/examples/statistics/bxp.py b/examples/statistics/bxp.py index 838fd8d118eb..bb06214f778a 100644 --- a/examples/statistics/bxp.py +++ b/examples/statistics/bxp.py @@ -1,6 +1,4 @@ """ -.. _statistics-bxp: - =================================== Demo of the boxplot drawer function =================================== diff --git a/examples/subplots_axes_and_figures/equal_aspect_ratio.py b/examples/subplots_axes_and_figures/equal_aspect_ratio.py index 7b8a742c93c2..86ebd5bc83fd 100644 --- a/examples/subplots_axes_and_figures/equal_aspect_ratio.py +++ b/examples/subplots_axes_and_figures/equal_aspect_ratio.py @@ -1,6 +1,4 @@ """ -.. _subplots_axes_and_figures-equal_aspect_ratio: - ================= Equal aspect axes ================= diff --git a/examples/user_interfaces/embedding_in_gtk2_sgskip.py b/examples/user_interfaces/embedding_in_gtk2_sgskip.py index 8df2876c0672..d8245cc8dda9 100644 --- a/examples/user_interfaces/embedding_in_gtk2_sgskip.py +++ b/examples/user_interfaces/embedding_in_gtk2_sgskip.py @@ -1,6 +1,4 @@ """ -.. _user_interfaces-embedding_in_gtk2: - ================= Embedding In GTK2 ================= diff --git a/examples/user_interfaces/embedding_in_qt4_sgskip.py b/examples/user_interfaces/embedding_in_qt4_sgskip.py index cad0bf101ce3..cad3582f261d 100644 --- a/examples/user_interfaces/embedding_in_qt4_sgskip.py +++ b/examples/user_interfaces/embedding_in_qt4_sgskip.py @@ -1,6 +1,4 @@ """ -.. _user_interfaces-embedding_in_qt4: - ================ Embedding In QT4 ================ diff --git a/examples/user_interfaces/embedding_in_tk_canvas_sgskip.py b/examples/user_interfaces/embedding_in_tk_canvas_sgskip.py index e60b8c1f7a2a..41380b758cd6 100644 --- a/examples/user_interfaces/embedding_in_tk_canvas_sgskip.py +++ b/examples/user_interfaces/embedding_in_tk_canvas_sgskip.py @@ -1,4 +1,3 @@ -# -*- noplot -*- """ ====================== Embedding in Tk Canvas diff --git a/examples/user_interfaces/embedding_in_tk_sgskip.py b/examples/user_interfaces/embedding_in_tk_sgskip.py index ded541a8459e..8def18952312 100644 --- a/examples/user_interfaces/embedding_in_tk_sgskip.py +++ b/examples/user_interfaces/embedding_in_tk_sgskip.py @@ -1,6 +1,4 @@ """ -.. _user_interfaces-embedding_in_tk: - =============== Embedding In Tk =============== diff --git a/examples/user_interfaces/embedding_in_wx2_sgskip.py b/examples/user_interfaces/embedding_in_wx2_sgskip.py index 0639aa5bdefc..6b8e9f2452da 100644 --- a/examples/user_interfaces/embedding_in_wx2_sgskip.py +++ b/examples/user_interfaces/embedding_in_wx2_sgskip.py @@ -1,6 +1,4 @@ """ -.. _user_interfaces-embedding_in_wx2: - ================ Embedding In Wx2 ================ diff --git a/examples/user_interfaces/mpl_with_glade_sgskip.py b/examples/user_interfaces/mpl_with_glade_sgskip.py index b3ebba27eac8..2a088a53e4cc 100644 --- a/examples/user_interfaces/mpl_with_glade_sgskip.py +++ b/examples/user_interfaces/mpl_with_glade_sgskip.py @@ -1,6 +1,4 @@ """ -.. _user_interfaces-mpl_with_glade: - ===================== Matplotlib With Glade ===================== diff --git a/examples/user_interfaces/toolmanager_sgskip.py b/examples/user_interfaces/toolmanager_sgskip.py index 9cf505444a04..0c77fe55e699 100644 --- a/examples/user_interfaces/toolmanager_sgskip.py +++ b/examples/user_interfaces/toolmanager_sgskip.py @@ -1,6 +1,4 @@ """ -.. _user_interfaces-toolmanager: - ============ Tool Manager ============ diff --git a/examples/widgets/polygon_selector_demo.py b/examples/widgets/polygon_selector_demo.py index 7126d2c78482..e692ccfa4935 100644 --- a/examples/widgets/polygon_selector_demo.py +++ b/examples/widgets/polygon_selector_demo.py @@ -1,6 +1,4 @@ """ -.. _widgets-polygon_selector_demo: - ===================== Polygon Selector Demo ===================== diff --git a/examples/widgets/span_selector.py b/examples/widgets/span_selector.py index b25d4497ac2f..140b45c001fd 100644 --- a/examples/widgets/span_selector.py +++ b/examples/widgets/span_selector.py @@ -1,6 +1,4 @@ """ -.. _widgets-span_selector: - ============= Span Selector ============= diff --git a/lib/matplotlib/axes/_axes.py b/lib/matplotlib/axes/_axes.py index ee9ff50c3634..83c9ba9a5076 100644 --- a/lib/matplotlib/axes/_axes.py +++ b/lib/matplotlib/axes/_axes.py @@ -501,7 +501,7 @@ def legend(self, *args, **kwargs): ----- Not all kinds of artist are supported by the legend command. - See :ref:`plotting-guide-legend` for details. + See :ref:`sphx_glr_tutorials_02_intermediate_legend_guide.py` for details. Examples -------- diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index 290090bb9999..4d25f3068b42 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1408,7 +1408,7 @@ def legend(self, *args, **kwargs): Notes ----- Not all kinds of artist are supported by the legend command. - See :ref:`plotting-guide-legend` for details. + See :ref:`sphx_glr_tutorials_02_intermediate_legend_guide.py` for details. """ # If no arguments given, collect up all the artists on the figure diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index d22e2e255381..b80f3dd05f3c 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -1434,7 +1434,7 @@ def thumbnail(infile, thumbfile, scale=0.1, interpolation='bilinear', .. htmlonly:: - :ref:`misc-image_thumbnail` + :ref:`sphx_glr_gallery_misc_image_thumbnail_sgskip.py` Return value is the figure instance containing the thumbnail diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index 21f87fa3a843..f391384293a9 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -7,7 +7,7 @@ It is unlikely that you would ever create a Legend instance manually. Most users would normally create a legend via the :meth:`~matplotlib.axes.Axes.legend` function. For more details on legends - there is also a :ref:`legend guide `. + there is also a :ref:`legend guide `. The Legend class can be considered as a container of legend handles and legend texts. Creation of corresponding legend handles from the @@ -17,7 +17,7 @@ handlers are defined in the :mod:`~matplotlib.legend_handler` module). Note that not all kinds of artist are supported by the legend yet by default but it is possible to extend the legend handler's capabilities to -support arbitrary objects. See the :ref:`legend guide ` +support arbitrary objects. See the :ref:`legend guide ` for more information. """ diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index 154f64bfbbba..94affe0e2171 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -2,7 +2,7 @@ This module defines default legend handlers. It is strongly encouraged to have read the :ref:`legend guide -` before this documentation. +` before this documentation. Legend handlers are expected to be a callable object with a following signature. :: diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index 6fd001ff9a76..1bb421753a1d 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -2,7 +2,7 @@ :mod:`~matplotlib.mathtext` is a module for parsing a subset of the TeX math syntax and drawing them to a matplotlib backend. -For a tutorial of its usage see :ref:`mathtext-tutorial`. This +For a tutorial of its usage see :ref:`sphx_glr_tutorials_text_mathtext.py`. This document is primarily concerned with implementation details. The module uses pyparsing_ to parse the TeX expression. diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index 07976372f550..ae16a696b500 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -163,7 +163,7 @@ ax.yaxis.set_major_formatter( ymajorFormatter ) ax.yaxis.set_minor_formatter( yminorFormatter ) -See :ref:`pylab_examples-major_minor_demo1` for an example of setting +See :ref:`sphx_glr_gallery_pylab_examples_major_minor_demo1.py` for an example of setting major and minor ticks. See the :mod:`matplotlib.dates` module for more information and examples of using date locators and formatters. """ diff --git a/lib/matplotlib/widgets.py b/lib/matplotlib/widgets.py index 3c4a829a37b7..aa27f80d7485 100644 --- a/lib/matplotlib/widgets.py +++ b/lib/matplotlib/widgets.py @@ -1701,7 +1701,7 @@ class SpanSelector(_SelectorWidget): rectprops=rectprops) >>> fig.show() - See also: :ref:`widgets-span_selector` + See also: :ref:`sphx_glr_gallery_widgets_span_selector.py` """ @@ -2534,7 +2534,7 @@ class PolygonSelector(_SelectorWidget): See Also -------- - :ref:`widgets-polygon_selector_demo` + :ref:`sphx_glr_gallery_widgets_polygon_selector_demo.py` """ def __init__(self, ax, onselect, useblit=False, diff --git a/tutorials/01_introductory/README.txt b/tutorials/01_introductory/README.txt new file mode 100644 index 000000000000..bc3c81830a8b --- /dev/null +++ b/tutorials/01_introductory/README.txt @@ -0,0 +1,8 @@ +.. _tutorials-introductory: + +Introductory +============ + +These tutorials cover the basics of creating visualizations with +Matplotlib, as well as some best-practices in using the package +effectively. diff --git a/tutorials/01_introductory/customizing.py b/tutorials/01_introductory/customizing.py new file mode 100644 index 000000000000..03b38b59ac09 --- /dev/null +++ b/tutorials/01_introductory/customizing.py @@ -0,0 +1,192 @@ +""" +Customizing matplotlib +====================== + +Tips for customizing the properties and default styles of matplotlib. + +Using style sheets +------------------ + +The ``style`` package adds support for easy-to-switch plotting "styles" with +the same parameters as a matplotlibrc_ file (which is read at startup to +configure matplotlib). + +There are a number of pre-defined styles provided by matplotlib. For +example, there's a pre-defined style called "ggplot", which emulates the +aesthetics of ggplot_ (a popular plotting package for R_). To use this style, +just add: +""" + +import numpy as np +import matplotlib.pyplot as plt +import matplotlib as mpl +plt.style.use('ggplot') +data = np.random.randn(50) + +############################################################################### +# To list all available styles, use: + +print(plt.style.available) + +############################################################################### +# Defining your own style +# ----------------------- +# +# You can create custom styles and use them by calling ``style.use`` with the +# path or URL to the style sheet. Additionally, if you add your +# ``.mplstyle`` file to ``mpl_configdir/stylelib``, you can reuse +# your custom style sheet with a call to ``style.use()``. By default +# ``mpl_configdir`` should be ``~/.config/matplotlib``, but you can check where +# yours is with ``matplotlib.get_configdir()``; you may need to create this +# directory. You also can change the directory where matplotlib looks for +# the stylelib/ folder by setting the MPLCONFIGDIR environment variable, +# see :ref:`locating-matplotlib-config-dir`. +# +# Note that a custom style sheet in ``mpl_configdir/stylelib`` will +# override a style sheet defined by matplotlib if the styles have the same name. +# +# For example, you might want to create +# ``mpl_configdir/stylelib/presentation.mplstyle`` with the following:: +# +# axes.titlesize : 24 +# axes.labelsize : 20 +# lines.linewidth : 3 +# lines.markersize : 10 +# xtick.labelsize : 16 +# ytick.labelsize : 16 +# +# Then, when you want to adapt a plot designed for a paper to one that looks +# good in a presentation, you can just add:: +# +# >>> import matplotlib.pyplot as plt +# >>> plt.style.use('presentation') +# +# +# Composing styles +# ---------------- +# +# Style sheets are designed to be composed together. So you can have a style +# sheet that customizes colors and a separate style sheet that alters element +# sizes for presentations. These styles can easily be combined by passing +# a list of styles:: +# +# >>> import matplotlib.pyplot as plt +# >>> plt.style.use(['dark_background', 'presentation']) +# +# Note that styles further to the right will overwrite values that are already +# defined by styles on the left. +# +# +# Temporary styling +# ----------------- +# +# If you only want to use a style for a specific block of code but don't want +# to change the global styling, the style package provides a context manager +# for limiting your changes to a specific scope. To isolate your styling +# changes, you can write something like the following: + +with plt.style.context(('dark_background')): + plt.plot(np.sin(np.linspace(0, 2 * np.pi)), 'r-o') +plt.show() + +############################################################################### +# matplotlib rcParams +# =================== +# +# .. _customizing-with-dynamic-rc-settings: +# +# Dynamic rc settings +# ------------------- +# +# You can also dynamically change the default rc settings in a python script or +# interactively from the python shell. All of the rc settings are stored in a +# dictionary-like variable called :data:`matplotlib.rcParams`, which is global to +# the matplotlib package. rcParams can be modified directly, for example: + +mpl.rcParams['lines.linewidth'] = 2 +mpl.rcParams['lines.color'] = 'r' +plt.plot(data) + +############################################################################### +# Matplotlib also provides a couple of convenience functions for modifying rc +# settings. The :func:`matplotlib.rc` command can be used to modify multiple +# settings in a single group at once, using keyword arguments: + +mpl.rc('lines', linewidth=4, color='g') +plt.plot(data) + +############################################################################### +# The :func:`matplotlib.rcdefaults` command will restore the standard matplotlib +# default settings. +# +# There is some degree of validation when setting the values of rcParams, see +# :mod:`matplotlib.rcsetup` for details. +# +# .. _customizing-with-matplotlibrc-files: +# +# The :file:`matplotlibrc` file +# ----------------------------- +# +# matplotlib uses :file:`matplotlibrc` configuration files to customize all kinds +# of properties, which we call `rc settings` or `rc parameters`. You can control +# the defaults of almost every property in matplotlib: figure size and dpi, line +# width, color and style, axes, axis and grid properties, text and font +# properties and so on. matplotlib looks for :file:`matplotlibrc` in four +# locations, in the following order: +# +# 1. :file:`matplotlibrc` in the current working directory, usually used for +# specific customizations that you do not want to apply elsewhere. +# +# 2. :file:`$MATPLOTLIBRC` if it is a file, else :file:`$MATPLOTLIBRC/matplotlibrc`. +# +# 3. It next looks in a user-specific place, depending on your platform: +# +# - On Linux and FreeBSD, it looks in :file:`.config/matplotlib/matplotlibrc` +# (or `$XDG_CONFIG_HOME/matplotlib/matplotlibrc`) if you've customized +# your environment. +# +# - On other platforms, it looks in :file:`.matplotlib/matplotlibrc`. +# +# See :ref:`locating-matplotlib-config-dir`. +# +# 4. :file:`{INSTALL}/matplotlib/mpl-data/matplotlibrc`, where +# :file:`{INSTALL}` is something like +# :file:`/usr/lib/python3.5/site-packages` on Linux, and maybe +# :file:`C:\\Python35\\Lib\\site-packages` on Windows. Every time you +# install matplotlib, this file will be overwritten, so if you want +# your customizations to be saved, please move this file to your +# user-specific matplotlib directory. +# +# Once a :file:`matplotlibrc` file has been found, it will *not* search any of +# the other paths. +# +# To display where the currently active :file:`matplotlibrc` file was +# loaded from, one can do the following:: +# +# >>> import matplotlib +# >>> matplotlib.matplotlib_fname() +# '/home/foo/.config/matplotlib/matplotlibrc' +# +# See below for a sample :ref:`matplotlibrc file`. +# Although all parameters are optional, you should almost always set the +# `backend` or else matplotlib will choose `Agg`, a *non-interactive* backend. +# This can lead to unexpected behavior, since if you do not have a +# :file:`matplotlibrc` file, it would normally fall back to +# :file:`{INSTALL}/matplotlib/mpl-data/matplotlibrc`, which is often set to an +# interactive backend by the package maintainer. +# +# .. _matplotlibrc-sample: +# +# A sample matplotlibrc file +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# .. htmlonly:: +# +# `(download) <../../_static/matplotlibrc>`__ +# +# .. literalinclude:: ../../_static/matplotlibrc +# +# +# .. _matplotlibrc: http://matplotlib.org/users/customizing.html +# .. _ggplot: http://ggplot2.org/ +# .. _R: https://www.r-project.org/ diff --git a/tutorials/01_introductory/images.py b/tutorials/01_introductory/images.py new file mode 100644 index 000000000000..0e83a01a8d61 --- /dev/null +++ b/tutorials/01_introductory/images.py @@ -0,0 +1,275 @@ +""" +============== +Image tutorial +============== + +A short tutorial on plotting images with Matplotlib. + +.. _imaging_startup: + +Startup commands +=================== + +First, let's start IPython. It is a most excellent enhancement to the +standard Python prompt, and it ties in especially well with +Matplotlib. Start IPython either at a shell, or the IPython Notebook now. + +With IPython started, we now need to connect to a GUI event loop. This +tells IPython where (and how) to display plots. To connect to a GUI +loop, execute the **%matplotlib** magic at your IPython prompt. There's more +detail on exactly what this does at `IPython's documentation on GUI +event loops +`_. + +If you're using IPython Notebook, the same commands are available, but +people commonly use a specific argument to the %matplotlib magic: + +.. sourcecode:: ipython + + In [1]: %matplotlib inline + +This turns on inline plotting, where plot graphics will appear in your +notebook. This has important implications for interactivity. For inline plotting, commands in +cells below the cell that outputs a plot will not affect the plot. For example, +changing the color map is not possible from cells below the cell that creates a plot. +However, for other backends, such as qt4, that open a separate window, +cells below those that create the plot will change the plot - it is a +live object in memory. + +This tutorial will use matplotlib's imperative-style plotting +interface, pyplot. This interface maintains global state, and is very +useful for quickly and easily experimenting with various plot +settings. The alternative is the object-oriented interface, which is also +very powerful, and generally more suitable for large application +development. If you'd like to learn about the object-oriented +interface, a great place to start is our `FAQ on usage +`_. For now, let's get on +with the imperative-style approach: +""" + +import matplotlib.pyplot as plt +import matplotlib.image as mpimg +import numpy as np + +############################################################################### +# .. _importing_data: +# +# Importing image data into Numpy arrays +# =============================================== +# +# Loading image data is supported by the `Pillow +# `_ library. Natively, matplotlib only +# supports PNG images. The commands shown below fall back on Pillow if the +# native read fails. +# +# The image used in this example is a PNG file, but keep that Pillow +# requirement in mind for your own data. +# +# Here's the image we're going to play with: +# +# .. image:: ../../_static/stinkbug.png +# +# It's a 24-bit RGB PNG image (8 bits for each of R, G, B). Depending +# on where you get your data, the other kinds of image that you'll most +# likely encounter are RGBA images, which allow for transparency, or +# single-channel grayscale (luminosity) images. You can right click on +# it and choose "Save image as" to download it to your computer for the +# rest of this tutorial. +# +# And here we go... + +img = mpimg.imread('../../doc/_static/stinkbug.png') +print(img) + +############################################################################### +# Note the dtype there - float32. Matplotlib has rescaled the 8 bit +# data from each channel to floating point data between 0.0 and 1.0. As +# a side note, the only datatype that Pillow can work with is uint8. +# Matplotlib plotting can handle float32 and uint8, but image +# reading/writing for any format other than PNG is limited to uint8 +# data. Why 8 bits? Most displays can only render 8 bits per channel +# worth of color gradation. Why can they only render 8 bits/channel? +# Because that's about all the human eye can see. More here (from a +# photography standpoint): `Luminous Landscape bit depth tutorial +# `_. +# +# Each inner list represents a pixel. Here, with an RGB image, there +# are 3 values. Since it's a black and white image, R, G, and B are all +# similar. An RGBA (where A is alpha, or transparency), has 4 values +# per inner list, and a simple luminance image just has one value (and +# is thus only a 2-D array, not a 3-D array). For RGB and RGBA images, +# matplotlib supports float32 and uint8 data types. For grayscale, +# matplotlib supports only float32. If your array data does not meet +# one of these descriptions, you need to rescale it. +# +# .. _plotting_data: +# +# Plotting numpy arrays as images +# =================================== +# +# So, you have your data in a numpy array (either by importing it, or by +# generating it). Let's render it. In Matplotlib, this is performed +# using the :func:`~matplotlib.pyplot.imshow` function. Here we'll grab +# the plot object. This object gives you an easy way to manipulate the +# plot from the prompt. + +imgplot = plt.imshow(img) + +############################################################################### +# You can also plot any numpy array. +# +# .. _Pseudocolor: +# +# Applying pseudocolor schemes to image plots +# ------------------------------------------------- +# +# Pseudocolor can be a useful tool for enhancing contrast and +# visualizing your data more easily. This is especially useful when +# making presentations of your data using projectors - their contrast is +# typically quite poor. +# +# Pseudocolor is only relevant to single-channel, grayscale, luminosity +# images. We currently have an RGB image. Since R, G, and B are all +# similar (see for yourself above or in your data), we can just pick one +# channel of our data: + +lum_img = img[:, :, 0] + +# This is array slicing. You can read more in the `Numpy tutorial +# `_. + +plt.imshow(lum_img) + +############################################################################### +# Now, with a luminosity (2D, no color) image, the default colormap (aka lookup table, +# LUT), is applied. The default is called viridis. There are plenty of +# others to choose from. + +plt.imshow(lum_img, cmap="hot") + +############################################################################### +# Note that you can also change colormaps on existing plot objects using the +# :meth:`~matplotlib.image.Image.set_cmap` method: + +imgplot = plt.imshow(lum_img) +imgplot.set_cmap('nipy_spectral') + +############################################################################### +# +# .. note:: +# +# However, remember that in the IPython notebook with the inline backend, +# you can't make changes to plots that have already been rendered. If you +# create imgplot here in one cell, you cannot call set_cmap() on it in a later +# cell and expect the earlier plot to change. Make sure that you enter these +# commands together in one cell. plt commands will not change plots from earlier +# cells. +# +# There are many other colormap schemes available. See the `list and +# images of the colormaps +# <../colors/colormaps.html>`_. +# +# .. _`Color Bars`: +# +# Color scale reference +# ------------------------ +# +# It's helpful to have an idea of what value a color represents. We can +# do that by adding color bars. + +imgplot = plt.imshow(lum_img) +plt.colorbar() + +############################################################################### +# This adds a colorbar to your existing figure. This won't +# automatically change if you change you switch to a different +# colormap - you have to re-create your plot, and add in the colorbar +# again. +# +# .. _`Data ranges`: +# +# Examining a specific data range +# --------------------------------- +# +# Sometimes you want to enhance the contrast in your image, or expand +# the contrast in a particular region while sacrificing the detail in +# colors that don't vary much, or don't matter. A good tool to find +# interesting regions is the histogram. To create a histogram of our +# image data, we use the :func:`~matplotlib.pyplot.hist` function. + +plt.hist(lum_img.ravel(), bins=256, range=(0.0, 1.0), fc='k', ec='k') + +############################################################################### +# Most often, the "interesting" part of the image is around the peak, +# and you can get extra contrast by clipping the regions above and/or +# below the peak. In our histogram, it looks like there's not much +# useful information in the high end (not many white things in the +# image). Let's adjust the upper limit, so that we effectively "zoom in +# on" part of the histogram. We do this by passing the clim argument to +# imshow. You could also do this by calling the +# :meth:`~matplotlib.image.Image.set_clim` method of the image plot +# object, but make sure that you do so in the same cell as your plot +# command when working with the IPython Notebook - it will not change +# plots from earlier cells. +# +# You can specify the clim in the call to ``plot``. + +imgplot = plt.imshow(lum_img, clim=(0.0, 0.7)) + +############################################################################### +# You can also specify the clim using the returned object +fig = plt.figure() +a = fig.add_subplot(1, 2, 1) +imgplot = plt.imshow(lum_img) +a.set_title('Before') +plt.colorbar(ticks=[0.1, 0.3, 0.5, 0.7], orientation='horizontal') +a = fig.add_subplot(1, 2, 2) +imgplot = plt.imshow(lum_img) +imgplot.set_clim(0.0, 0.7) +a.set_title('After') +plt.colorbar(ticks=[0.1, 0.3, 0.5, 0.7], orientation='horizontal') + +############################################################################### +# .. _Interpolation: +# +# Array Interpolation schemes +# --------------------------- +# +# Interpolation calculates what the color or value of a pixel "should" +# be, according to different mathematical schemes. One common place +# that this happens is when you resize an image. The number of pixels +# change, but you want the same information. Since pixels are discrete, +# there's missing space. Interpolation is how you fill that space. +# This is why your images sometimes come out looking pixelated when you +# blow them up. The effect is more pronounced when the difference +# between the original image and the expanded image is greater. Let's +# take our image and shrink it. We're effectively discarding pixels, +# only keeping a select few. Now when we plot it, that data gets blown +# up to the size on your screen. The old pixels aren't there anymore, +# and the computer has to draw in pixels to fill that space. +# +# We'll use the Pillow library that we used to load the image also to resize +# the image. + +from PIL import Image + +img = Image.open('../../doc/_static/stinkbug.png') +img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place +imgplot = plt.imshow(img) + +############################################################################### +# Here we have the default interpolation, bilinear, since we did not +# give :func:`~matplotlib.pyplot.imshow` any interpolation argument. +# +# Let's try some others. Here's "nearest", which does no interpolation. + +imgplot = plt.imshow(img, interpolation="nearest") + +############################################################################### +# and bucibic: + +imgplot = plt.imshow(img, interpolation="bicubic") + +############################################################################### +# Bicubic interpolation is often used when blowing up photos - people +# tend to prefer blurry over pixelated. diff --git a/tutorials/01_introductory/pyplot.py b/tutorials/01_introductory/pyplot.py new file mode 100644 index 000000000000..236226153c26 --- /dev/null +++ b/tutorials/01_introductory/pyplot.py @@ -0,0 +1,430 @@ +""" +=============== +Pyplot tutorial +=============== + +An introduction to the pyplot interface. + +""" + +############################################################################### +# Intro to pyplot +# =============== +# +# :mod:`matplotlib.pyplot` is a collection of command style functions +# that make matplotlib work like MATLAB. +# Each ``pyplot`` function makes +# some change to a figure: e.g., creates a figure, creates a plotting area +# in a figure, plots some lines in a plotting area, decorates the plot +# with labels, etc. +# +# In :mod:`matplotlib.pyplot` various states are preserved +# across function calls, so that it keeps track of things like +# the current figure and plotting area, and the plotting +# functions are directed to the current axes (please note that "axes" here +# and in most places in the documentation refers to the *axes* +# `part of a figure `__ +# and not the strict mathematical term for more than one axis). +# +# .. note:: +# +# the pyplot API is generally less-flexible than the object-oriented API. +# Most of the function calls you see here can also be called as methods +# from an ``Axes`` object. We recommend browsing the tutorials and +# examples to see how this works. +# +# Generating visualizations with pyplot is very quick: + +import matplotlib.pyplot as plt +plt.plot([1, 2, 3, 4]) +plt.ylabel('some numbers') +plt.show() + +############################################################################### +# You may be wondering why the x-axis ranges from 0-3 and the y-axis +# from 1-4. If you provide a single list or array to the +# :func:`~matplotlib.pyplot.plot` command, matplotlib assumes it is a +# sequence of y values, and automatically generates the x values for +# you. Since python ranges start with 0, the default x vector has the +# same length as y but starts with 0. Hence the x data are +# ``[0,1,2,3]``. +# +# :func:`~matplotlib.pyplot.plot` is a versatile command, and will take +# an arbitrary number of arguments. For example, to plot x versus y, +# you can issue the command:: + +plt.plot([1, 2, 3, 4], [1, 4, 9, 16]) + +############################################################################### +# Formatting the style of your plot +# --------------------------------- +# +# For every x, y pair of arguments, there is an optional third argument +# which is the format string that indicates the color and line type of +# the plot. The letters and symbols of the format string are from +# MATLAB, and you concatenate a color string with a line style string. +# The default format string is 'b-', which is a solid blue line. For +# example, to plot the above with red circles, you would issue + +plt.plot([1, 2, 3, 4], [1, 4, 9, 16], 'ro') +plt.axis([0, 6, 0, 20]) +plt.show() + +############################################################################### +# See the :func:`~matplotlib.pyplot.plot` documentation for a complete +# list of line styles and format strings. The +# :func:`~matplotlib.pyplot.axis` command in the example above takes a +# list of ``[xmin, xmax, ymin, ymax]`` and specifies the viewport of the +# axes. +# +# If matplotlib were limited to working with lists, it would be fairly +# useless for numeric processing. Generally, you will use `numpy +# `_ arrays. In fact, all sequences are +# converted to numpy arrays internally. The example below illustrates a +# plotting several lines with different format styles in one command +# using arrays. + +import numpy as np + +# evenly sampled time at 200ms intervals +t = np.arange(0., 5., 0.2) + +# red dashes, blue squares and green triangles +plt.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^') +plt.show() + +############################################################################### +# .. _controlling-line-properties: +# +# Controlling line properties +# =========================== +# +# Lines have many attributes that you can set: linewidth, dash style, +# antialiased, etc; see :class:`matplotlib.lines.Line2D`. There are +# several ways to set line properties +# +# * Use keyword args:: +# +# plt.plot(x, y, linewidth=2.0) +# +# +# * Use the setter methods of a ``Line2D`` instance. ``plot`` returns a list +# of ``Line2D`` objects; e.g., ``line1, line2 = plot(x1, y1, x2, y2)``. In the code +# below we will suppose that we have only +# one line so that the list returned is of length 1. We use tuple unpacking with +# ``line,`` to get the first element of that list:: +# +# line, = plt.plot(x, y, '-') +# line.set_antialiased(False) # turn off antialising +# +# * Use the :func:`~matplotlib.pyplot.setp` command. The example below +# uses a MATLAB-style command to set multiple properties +# on a list of lines. ``setp`` works transparently with a list of objects +# or a single object. You can either use python keyword arguments or +# MATLAB-style string/value pairs:: +# +# lines = plt.plot(x1, y1, x2, y2) +# # use keyword args +# plt.setp(lines, color='r', linewidth=2.0) +# # or MATLAB style string value pairs +# plt.setp(lines, 'color', 'r', 'linewidth', 2.0) +# +# +# Here are the available :class:`~matplotlib.lines.Line2D` properties. +# +# ====================== ================================================== +# Property Value Type +# ====================== ================================================== +# alpha float +# animated [True | False] +# antialiased or aa [True | False] +# clip_box a matplotlib.transform.Bbox instance +# clip_on [True | False] +# clip_path a Path instance and a Transform instance, a Patch +# color or c any matplotlib color +# contains the hit testing function +# dash_capstyle [``'butt'`` | ``'round'`` | ``'projecting'``] +# dash_joinstyle [``'miter'`` | ``'round'`` | ``'bevel'``] +# dashes sequence of on/off ink in points +# data (np.array xdata, np.array ydata) +# figure a matplotlib.figure.Figure instance +# label any string +# linestyle or ls [ ``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'steps'`` | ...] +# linewidth or lw float value in points +# lod [True | False] +# marker [ ``'+'`` | ``','`` | ``'.'`` | ``'1'`` | ``'2'`` | ``'3'`` | ``'4'`` ] +# markeredgecolor or mec any matplotlib color +# markeredgewidth or mew float value in points +# markerfacecolor or mfc any matplotlib color +# markersize or ms float +# markevery [ None | integer | (startind, stride) ] +# picker used in interactive line selection +# pickradius the line pick selection radius +# solid_capstyle [``'butt'`` | ``'round'`` | ``'projecting'``] +# solid_joinstyle [``'miter'`` | ``'round'`` | ``'bevel'``] +# transform a matplotlib.transforms.Transform instance +# visible [True | False] +# xdata np.array +# ydata np.array +# zorder any number +# ====================== ================================================== +# +# To get a list of settable line properties, call the +# :func:`~matplotlib.pyplot.setp` function with a line or lines +# as argument +# +# .. sourcecode:: ipython +# +# In [69]: lines = plt.plot([1, 2, 3]) +# +# In [70]: plt.setp(lines) +# alpha: float +# animated: [True | False] +# antialiased or aa: [True | False] +# ...snip +# +# .. _multiple-figs-axes: +# +# +# Working with multiple figures and axes +# ====================================== +# +# MATLAB, and :mod:`~matplotlib.pyplot`, have the concept of the current +# figure and the current axes. All plotting commands apply to the +# current axes. The function :func:`~matplotlib.pyplot.gca` returns the +# current axes (a :class:`matplotlib.axes.Axes` instance), and +# :func:`~matplotlib.pyplot.gcf` returns the current figure +# (:class:`matplotlib.figure.Figure` instance). Normally, you don't have +# to worry about this, because it is all taken care of behind the +# scenes. Below is a script to create two subplots. + + +def f(t): + return np.exp(-t) * np.cos(2*np.pi*t) + +t1 = np.arange(0.0, 5.0, 0.1) +t2 = np.arange(0.0, 5.0, 0.02) + +plt.figure(1) +plt.subplot(211) +plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k') + +plt.subplot(212) +plt.plot(t2, np.cos(2*np.pi*t2), 'r--') +plt.show() + +############################################################################### +# The :func:`~matplotlib.pyplot.figure` command here is optional because +# ``figure(1)`` will be created by default, just as a ``subplot(111)`` +# will be created by default if you don't manually specify any axes. The +# :func:`~matplotlib.pyplot.subplot` command specifies ``numrows, +# numcols, fignum`` where ``fignum`` ranges from 1 to +# ``numrows*numcols``. The commas in the ``subplot`` command are +# optional if ``numrows*numcols<10``. So ``subplot(211)`` is identical +# to ``subplot(2, 1, 1)``. +# +# You can create an arbitrary number of subplots +# and axes. If you want to place an axes manually, i.e., not on a +# rectangular grid, use the :func:`~matplotlib.pyplot.axes` command, +# which allows you to specify the location as ``axes([left, bottom, +# width, height])`` where all values are in fractional (0 to 1) +# coordinates. See :ref:`sphx_glr_gallery_pylab_examples_axes_demo.py` for an example of +# placing axes manually and :ref:`sphx_glr_gallery_pylab_examples_subplot_demo.py` for an +# example with lots of subplots. +# +# +# You can create multiple figures by using multiple +# :func:`~matplotlib.pyplot.figure` calls with an increasing figure +# number. Of course, each figure can contain as many axes and subplots +# as your heart desires:: +# +# import matplotlib.pyplot as plt +# plt.figure(1) # the first figure +# plt.subplot(211) # the first subplot in the first figure +# plt.plot([1, 2, 3]) +# plt.subplot(212) # the second subplot in the first figure +# plt.plot([4, 5, 6]) +# +# +# plt.figure(2) # a second figure +# plt.plot([4, 5, 6]) # creates a subplot(111) by default +# +# plt.figure(1) # figure 1 current; subplot(212) still current +# plt.subplot(211) # make subplot(211) in figure1 current +# plt.title('Easy as 1, 2, 3') # subplot 211 title +# +# You can clear the current figure with :func:`~matplotlib.pyplot.clf` +# and the current axes with :func:`~matplotlib.pyplot.cla`. If you find +# it annoying that states (specifically the current image, figure and axes) +# are being maintained for you behind the scenes, don't despair: this is just a thin +# stateful wrapper around an object oriented API, which you can use +# instead (see :ref:`sphx_glr_tutorials_02_intermediate_artists.py`) +# +# If you are making lots of figures, you need to be aware of one +# more thing: the memory required for a figure is not completely +# released until the figure is explicitly closed with +# :func:`~matplotlib.pyplot.close`. Deleting all references to the +# figure, and/or using the window manager to kill the window in which +# the figure appears on the screen, is not enough, because pyplot +# maintains internal references until :func:`~matplotlib.pyplot.close` +# is called. +# +# .. _working-with-text: +# +# Working with text +# ================= +# +# The :func:`~matplotlib.pyplot.text` command can be used to add text in +# an arbitrary location, and the :func:`~matplotlib.pyplot.xlabel`, +# :func:`~matplotlib.pyplot.ylabel` and :func:`~matplotlib.pyplot.title` +# are used to add text in the indicated locations (see :ref:`sphx_glr_tutorials_text_text_intro.py` +# for a more detailed example) + +mu, sigma = 100, 15 +x = mu + sigma * np.random.randn(10000) + +# the histogram of the data +n, bins, patches = plt.hist(x, 50, normed=1, facecolor='g', alpha=0.75) + + +plt.xlabel('Smarts') +plt.ylabel('Probability') +plt.title('Histogram of IQ') +plt.text(60, .025, r'$\mu=100,\ \sigma=15$') +plt.axis([40, 160, 0, 0.03]) +plt.grid(True) +plt.show() + +############################################################################### +# All of the :func:`~matplotlib.pyplot.text` commands return an +# :class:`matplotlib.text.Text` instance. Just as with with lines +# above, you can customize the properties by passing keyword arguments +# into the text functions or using :func:`~matplotlib.pyplot.setp`:: +# +# t = plt.xlabel('my data', fontsize=14, color='red') +# +# These properties are covered in more detail in :ref:`sphx_glr_tutorials_text_text_props.py`. +# +# +# Using mathematical expressions in text +# -------------------------------------- +# +# matplotlib accepts TeX equation expressions in any text expression. +# For example to write the expression :math:`\sigma_i=15` in the title, +# you can write a TeX expression surrounded by dollar signs:: +# +# plt.title(r'$\sigma_i=15$') +# +# The ``r`` preceding the title string is important -- it signifies +# that the string is a *raw* string and not to treat backslashes as +# python escapes. matplotlib has a built-in TeX expression parser and +# layout engine, and ships its own math fonts -- for details see +# :ref:`sphx_glr_tutorials_text_mathtext.py`. Thus you can use mathematical text across platforms +# without requiring a TeX installation. For those who have LaTeX and +# dvipng installed, you can also use LaTeX to format your text and +# incorporate the output directly into your display figures or saved +# postscript -- see :ref:`sphx_glr_tutorials_text_usetex.py`. +# +# +# Annotating text +# --------------- +# +# The uses of the basic :func:`~matplotlib.pyplot.text` command above +# place text at an arbitrary position on the Axes. A common use for +# text is to annotate some feature of the plot, and the +# :func:`~matplotlib.pyplot.annotate` method provides helper +# functionality to make annotations easy. In an annotation, there are +# two points to consider: the location being annotated represented by +# the argument ``xy`` and the location of the text ``xytext``. Both of +# these arguments are ``(x,y)`` tuples. + +ax = plt.subplot(111) + +t = np.arange(0.0, 5.0, 0.01) +s = np.cos(2*np.pi*t) +line, = plt.plot(t, s, lw=2) + +plt.annotate('local max', xy=(2, 1), xytext=(3, 1.5), + arrowprops=dict(facecolor='black', shrink=0.05), + ) + +plt.ylim(-2, 2) +plt.show() + +############################################################################### +# In this basic example, both the ``xy`` (arrow tip) and ``xytext`` +# locations (text location) are in data coordinates. There are a +# variety of other coordinate systems one can choose -- see +# :ref:`annotations-tutorial` and :ref:`plotting-guide-annotation` for +# details. More examples can be found in +# :ref:`sphx_glr_gallery_pylab_examples_annotation_demo.py`. +# +# +# Logarithmic and other nonlinear axes +# ==================================== +# +# :mod:`matplotlib.pyplot` supports not only linear axis scales, but also +# logarithmic and logit scales. This is commonly used if data spans many orders +# of magnitude. Changing the scale of an axis is easy: +# +# plt.xscale('log') +# +# An example of four plots with the same data and different scales for the y axis +# is shown below. + +from matplotlib.ticker import NullFormatter # useful for `logit` scale + +# Fixing random state for reproducibility +np.random.seed(19680801) + +# make up some data in the interval ]0, 1[ +y = np.random.normal(loc=0.5, scale=0.4, size=1000) +y = y[(y > 0) & (y < 1)] +y.sort() +x = np.arange(len(y)) + +# plot with various axes scales +plt.figure(1) + +# linear +plt.subplot(221) +plt.plot(x, y) +plt.yscale('linear') +plt.title('linear') +plt.grid(True) + + +# log +plt.subplot(222) +plt.plot(x, y) +plt.yscale('log') +plt.title('log') +plt.grid(True) + + +# symmetric log +plt.subplot(223) +plt.plot(x, y - y.mean()) +plt.yscale('symlog', linthreshy=0.01) +plt.title('symlog') +plt.grid(True) + +# logit +plt.subplot(224) +plt.plot(x, y) +plt.yscale('logit') +plt.title('logit') +plt.grid(True) +# Format the minor tick labels of the y-axis into empty strings with +# `NullFormatter`, to avoid cumbering the axis with too many labels. +plt.gca().yaxis.set_minor_formatter(NullFormatter()) +# Adjust the subplot layout, because the logit one may take more space +# than usual, due to y-tick labels like "1 - 10^{-3}" +plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25, + wspace=0.35) + +plt.show() + +############################################################################### +# It is also possible to add your own scale, see :ref:`adding-new-scales` for +# details. diff --git a/tutorials/01_introductory/usage.py b/tutorials/01_introductory/usage.py new file mode 100644 index 000000000000..0d803fb8c6ff --- /dev/null +++ b/tutorials/01_introductory/usage.py @@ -0,0 +1,627 @@ +""" +*********** +Usage Guide +*********** + +This tutorial covers some basic usage patterns and best-practices to +help you get started with Matplotlib. + +.. _general_concepts: + +General Concepts +================ + +:mod:`matplotlib` has an extensive codebase that can be daunting to many +new users. However, most of matplotlib can be understood with a fairly +simple conceptual framework and knowledge of a few important points. + +Plotting requires action on a range of levels, from the most general +(e.g., 'contour this 2-D array') to the most specific (e.g., 'color +this screen pixel red'). The purpose of a plotting package is to assist +you in visualizing your data as easily as possible, with all the necessary +control -- that is, by using relatively high-level commands most of +the time, and still have the ability to use the low-level commands when +needed. + +Therefore, everything in matplotlib is organized in a hierarchy. At the top +of the hierarchy is the matplotlib "state-machine environment" which is +provided by the :mod:`matplotlib.pyplot` module. At this level, simple +functions are used to add plot elements (lines, images, text, etc.) to +the current axes in the current figure. + +.. note:: + + Pyplot's state-machine environment behaves similarly to MATLAB and + should be most familiar to users with MATLAB experience. + +The next level down in the hierarchy is the first level of the object-oriented +interface, in which pyplot is used only for a few functions such as figure +creation, and the user explicitly creates and keeps track of the figure +and axes objects. At this level, the user uses pyplot to create figures, +and through those figures, one or more axes objects can be created. These +axes objects are then used for most plotting actions. + +For even more control -- which is essential for things like embedding +matplotlib plots in GUI applications -- the pyplot level may be dropped +completely, leaving a purely object-oriented approach. +""" + +# sphinx_gallery_thumbnail_number = 3 +import matplotlib.pyplot as plt +import numpy as np + +############################################################################### +# .. _figure_parts: +# +# Parts of a Figure +# ================= +# +# .. image:: ../../_static/anatomy.png +# +# +# :class:`~matplotlib.figure.Figure` +# ---------------------------------- +# +# The **whole** figure. The figure keeps +# track of all the child :class:`~matplotlib.axes.Axes`, a smattering of +# 'special' artists (titles, figure legends, etc), and the **canvas**. +# (Don't worry too much about the canvas, it is crucial as it is the +# object that actually does the drawing to get you your plot, but as the +# user it is more-or-less invisible to you). A figure can have any +# number of :class:`~matplotlib.axes.Axes`, but to be useful should have +# at least one. +# +# The easiest way to create a new figure is with pyplot: + +fig = plt.figure() # an empty figure with no axes +fig.suptitle('No axes on this figure') # Add a title so we know which it is + +fig, ax_lst = plt.subplots(2, 2) # a figure with a 2x2 grid of Axes + + +############################################################################### +# :class:`~matplotlib.axes.Axes` +# ------------------------------ +# +# This is what you think of as 'a plot', it is the region of the image +# with the data space (marked as the inner blue box). A given figure +# can contain many Axes, but a given :class:`~matplotlib.axes.Axes` +# object can only be in one :class:`~matplotlib.figure.Figure`. The +# Axes contains two (or three in the case of 3D) +# :class:`~matplotlib.axis.Axis` objects (be aware of the difference +# between **Axes** and **Axis**) which take care of the data limits (the +# data limits can also be controlled via set via the +# :meth:`~matplotlib.axes.Axes.set_xlim` and +# :meth:`~matplotlib.axes.Axes.set_ylim` :class:`Axes` methods). Each +# :class:`Axes` has a title (set via +# :meth:`~matplotlib.axes.Axes.set_title`), an x-label (set via +# :meth:`~matplotlib.axes.Axes.set_xlabel`), and a y-label set via +# :meth:`~matplotlib.axes.Axes.set_ylabel`). +# +# The :class:`Axes` class and it's member functions are the primary entry +# point to working with the OO interface. +# +# :class:`~matplotlib.axis.Axis` +# ------------------------------ +# +# These are the number-line-like objects (circled in green). They take +# care of setting the graph limits and generating the ticks (the marks +# on the axis) and ticklabels (strings labeling the ticks). The +# location of the ticks is determined by a +# :class:`~matplotlib.ticker.Locator` object and the ticklabel strings +# are formatted by a :class:`~matplotlib.ticker.Formatter`. The +# combination of the correct :class:`Locator` and :class:`Formatter` gives +# very fine control over the tick locations and labels. +# +# :class:`~matplotlib.artist.Artist` +# ---------------------------------- +# +# Basically everything you can see on the figure is an artist (even the +# :class:`Figure`, :class:`Axes`, and :class:`Axis` objects). This +# includes :class:`Text` objects, :class:`Line2D` objects, +# :class:`collection` objects, :class:`Patch` objects ... (you get the +# idea). When the figure is rendered, all of the artists are drawn to +# the **canvas**. Most Artists are tied to an Axes; such an Artist +# cannot be shared by multiple Axes, or moved from one to another. +# +# .. _input_types: +# +# Types of inputs to plotting functions +# ===================================== +# +# All of plotting functions expect `np.array` or `np.ma.masked_array` as +# input. Classes that are 'array-like' such as `pandas` data objects +# and `np.matrix` may or may not work as intended. It is best to +# convert these to `np.array` objects prior to plotting. +# +# For example, to convert a `pandas.DataFrame` :: +# +# a = pandas.DataFrame(np.random.rand(4,5), columns = list('abcde')) +# a_asndarray = a.values +# +# and to covert a `np.matrix` :: +# +# b = np.matrix([[1,2],[3,4]]) +# b_asarray = np.asarray(b) +# +# .. _pylab: +# +# Matplotlib, pyplot and pylab: how are they related? +# ==================================================== +# +# Matplotlib is the whole package; :mod:`matplotlib.pyplot` +# is a module in matplotlib; and :mod:`pylab` is a module +# that gets installed alongside :mod:`matplotlib`. +# +# Pyplot provides the state-machine interface to the underlying +# object-oriented plotting library. The state-machine implicitly and +# automatically creates figures and axes to achieve the desired +# plot. For example: + +x = np.linspace(0, 2, 100) + +plt.plot(x, x, label='linear') +plt.plot(x, x**2, label='quadratic') +plt.plot(x, x**3, label='cubic') + +plt.xlabel('x label') +plt.ylabel('y label') + +plt.title("Simple Plot") + +plt.legend() + +plt.show() + +############################################################################### +# The first call to ``plt.plot`` will automatically create the necessary +# figure and axes to achieve the desired plot. Subsequent calls to +# ``plt.plot`` re-use the current axes and each add another line. +# Setting the title, legend, and axis labels also automatically use the +# current axes and set the title, create the legend, and label the axis +# respectively. +# +# :mod:`pylab` is a convenience module that bulk imports +# :mod:`matplotlib.pyplot` (for plotting) and :mod:`numpy` +# (for mathematics and working with arrays) in a single name space. +# Although many examples use :mod:`pylab`, it is no longer recommended. +# +# For non-interactive plotting it is suggested +# to use pyplot to create the figures and then the OO interface for +# plotting. +# +# .. _coding_styles: +# +# Coding Styles +# ================== +# +# When viewing this documentation and examples, you will find different +# coding styles and usage patterns. These styles are perfectly valid +# and have their pros and cons. Just about all of the examples can be +# converted into another style and achieve the same results. +# The only caveat is to avoid mixing the coding styles for your own code. +# +# .. note:: +# Developers for matplotlib have to follow a specific style and guidelines. +# See :ref:`developers-guide-index`. +# +# Of the different styles, there are two that are officially supported. +# Therefore, these are the preferred ways to use matplotlib. +# +# For the pyplot style, the imports at the top of your +# scripts will typically be:: +# +# import matplotlib.pyplot as plt +# import numpy as np +# +# Then one calls, for example, np.arange, np.zeros, np.pi, plt.figure, +# plt.plot, plt.show, etc. Use the pyplot interface +# for creating figures, and then use the object methods for the rest: + +x = np.arange(0, 10, 0.2) +y = np.sin(x) +fig = plt.figure() +ax = fig.add_subplot(111) +ax.plot(x, y) +plt.show() + +############################################################################### +# So, why all the extra typing instead of the MATLAB-style (which relies +# on global state and a flat namespace)? For very simple things like +# this example, the only advantage is academic: the wordier styles are +# more explicit, more clear as to where things come from and what is +# going on. For more complicated applications, this explicitness and +# clarity becomes increasingly valuable, and the richer and more +# complete object-oriented interface will likely make the program easier +# to write and maintain. +# +# +# Typically one finds oneself making the same plots over and over +# again, but with different data sets, which leads to needing to write +# specialized functions to do the plotting. The recommended function +# signature is something like: + + +def my_plotter(ax, data1, data2, param_dict): + """ + A helper function to make a graph + + Parameters + ---------- + ax : Axes + The axes to draw to + + data1 : array + The x data + + data2 : array + The y data + + param_dict : dict + Dictionary of kwargs to pass to ax.plot + + Returns + ------- + out : list + list of artists added + """ + out = ax.plot(data1, data2, **param_dict) + return out + +# which you would then use as: + +data1, data2, data3, data4 = np.random.randn(4, 100) +fig, ax = plt.subplots(1, 1) +my_plotter(ax, data1, data2, {'marker': 'x'}) + +############################################################################### +# or if you wanted to have 2 sub-plots: +fig, (ax1, ax2) = plt.subplots(1, 2) +my_plotter(ax1, data1, data2, {'marker': 'x'}) +my_plotter(ax2, data3, data4, {'marker': 'o'}) + +############################################################################### +# Again, for these simple examples this style seems like overkill, however +# once the graphs get slightly more complex it pays off. +# +# .. _what-is-a-backend: +# +# What is a backend? +# ================== +# +# A lot of documentation on the website and in the mailing lists refers +# to the "backend" and many new users are confused by this term. +# matplotlib targets many different use cases and output formats. Some +# people use matplotlib interactively from the python shell and have +# plotting windows pop up when they type commands. Some people embed +# matplotlib into graphical user interfaces like wxpython or pygtk to +# build rich applications. Others use matplotlib in batch scripts to +# generate postscript images from some numerical simulations, and still +# others in web application servers to dynamically serve up graphs. +# +# To support all of these use cases, matplotlib can target different +# outputs, and each of these capabilities is called a backend; the +# "frontend" is the user facing code, i.e., the plotting code, whereas the +# "backend" does all the hard work behind-the-scenes to make the figure. +# There are two types of backends: user interface backends (for use in +# pygtk, wxpython, tkinter, qt4, or macosx; also referred to as +# "interactive backends") and hardcopy backends to make image files +# (PNG, SVG, PDF, PS; also referred to as "non-interactive backends"). +# +# There are four ways to configure your backend. If they conflict each other, +# the method mentioned last in the following list will be used, e.g. calling +# :func:`~matplotlib.use()` will override the setting in your ``matplotlibrc``. +# +# +# #. The ``backend`` parameter in your ``matplotlibrc`` file (see +# :ref:`sphx_glr_tutorials_01_introductory_customizing.py`):: +# +# backend : WXAgg # use wxpython with antigrain (agg) rendering +# +# #. Setting the :envvar:`MPLBACKEND` environment +# variable, either for your current shell or for a single script:: +# +# > export MPLBACKEND="module://my_backend" +# > python simple_plot.py +# +# > MPLBACKEND="module://my_backend" python simple_plot.py +# +# Setting this environment variable will override the ``backend`` parameter +# in *any* ``matplotlibrc``, even if there is a ``matplotlibrc`` in your +# current working directory. Therefore setting :envvar:`MPLBACKEND` +# globally, e.g. in your ``.bashrc`` or ``.profile``, is discouraged as it +# might lead to counter-intuitive behavior. +# +# #. If your script depends on a specific backend you can use the +# :func:`~matplotlib.use` function:: +# +# import matplotlib +# matplotlib.use('PS') # generate postscript output by default +# +# If you use the :func:`~matplotlib.use` function, this must be done before +# importing :mod:`matplotlib.pyplot`. Calling :func:`~matplotlib.use` after +# pyplot has been imported will have no effect. Using +# :func:`~matplotlib.use` will require changes in your code if users want to +# use a different backend. Therefore, you should avoid explicitly calling +# :func:`~matplotlib.use` unless absolutely necessary. +# +# .. note:: +# Backend name specifications are not case-sensitive; e.g., 'GTKAgg' +# and 'gtkagg' are equivalent. +# +# With a typical installation of matplotlib, such as from a +# binary installer or a linux distribution package, a good default +# backend will already be set, allowing both interactive work and +# plotting from scripts, with output to the screen and/or to +# a file, so at least initially you will not need to use any of the +# methods given above. +# +# If, however, you want to write graphical user interfaces, or a web +# application server (:ref:`howto-webapp`), or need a better +# understanding of what is going on, read on. To make things a little +# more customizable for graphical user interfaces, matplotlib separates +# the concept of the renderer (the thing that actually does the drawing) +# from the canvas (the place where the drawing goes). The canonical +# renderer for user interfaces is ``Agg`` which uses the `Anti-Grain +# Geometry`_ C++ library to make a raster (pixel) image of the figure. +# All of the user interfaces except ``macosx`` can be used with +# agg rendering, e.g., +# ``WXAgg``, ``GTKAgg``, ``QT4Agg``, ``QT5Agg``, ``TkAgg``. In +# addition, some of the user interfaces support other rendering engines. +# For example, with GTK, you can also select GDK rendering (backend +# ``GTK`` deprecated in 2.0) or Cairo rendering (backend ``GTKCairo``). +# +# For the rendering engines, one can also distinguish between `vector +# `_ or `raster +# `_ renderers. Vector +# graphics languages issue drawing commands like "draw a line from this +# point to this point" and hence are scale free, and raster backends +# generate a pixel representation of the line whose accuracy depends on a +# DPI setting. +# +# Here is a summary of the matplotlib renderers (there is an eponymous +# backed for each; these are *non-interactive backends*, capable of +# writing to a file): +# +# ============= ============ ================================================ +# Renderer Filetypes Description +# ============= ============ ================================================ +# :term:`AGG` :term:`png` :term:`raster graphics` -- high quality images +# using the `Anti-Grain Geometry`_ engine +# PS :term:`ps` :term:`vector graphics` -- Postscript_ output +# :term:`eps` +# PDF :term:`pdf` :term:`vector graphics` -- +# `Portable Document Format`_ +# SVG :term:`svg` :term:`vector graphics` -- +# `Scalable Vector Graphics`_ +# :term:`Cairo` :term:`png` :term:`vector graphics` -- +# :term:`ps` `Cairo graphics`_ +# :term:`pdf` +# :term:`svg` +# ... +# :term:`GDK` :term:`png` :term:`raster graphics` -- +# :term:`jpg` the `Gimp Drawing Kit`_ Deprecated in 2.0 +# :term:`tiff` +# ... +# ============= ============ ================================================ +# +# And here are the user interfaces and renderer combinations supported; +# these are *interactive backends*, capable of displaying to the screen +# and of using appropriate renderers from the table above to write to +# a file: +# +# ============ ================================================================ +# Backend Description +# ============ ================================================================ +# GTKAgg Agg rendering to a :term:`GTK` 2.x canvas (requires PyGTK_ and +# pycairo_ or cairocffi_; Python2 only) +# GTK3Agg Agg rendering to a :term:`GTK` 3.x canvas (requires PyGObject_ +# and pycairo_ or cairocffi_) +# GTK GDK rendering to a :term:`GTK` 2.x canvas (not recommended and d +# eprecated in 2.0) (requires PyGTK_ and pycairo_ or cairocffi_; +# Python2 only) +# GTKCairo Cairo rendering to a :term:`GTK` 2.x canvas (requires PyGTK_ +# and pycairo_ or cairocffi_; Python2 only) +# GTK3Cairo Cairo rendering to a :term:`GTK` 3.x canvas (requires PyGObject_ +# and pycairo_ or cairocffi_) +# WXAgg Agg rendering to to a :term:`wxWidgets` canvas +# (requires wxPython_) +# WX Native :term:`wxWidgets` drawing to a :term:`wxWidgets` Canvas +# (not recommended and deprecated in 2.0) (requires wxPython_) +# TkAgg Agg rendering to a :term:`Tk` canvas (requires TkInter_) +# Qt4Agg Agg rendering to a :term:`Qt4` canvas (requires PyQt4_ or ``pyside``) +# Qt5Agg Agg rendering in a :term:`Qt5` canvas (requires PyQt5_) +# macosx Cocoa rendering in OSX windows +# (presently lacks blocking show() behavior when matplotlib +# is in non-interactive mode) +# ============ ================================================================ +# +# .. _`Anti-Grain Geometry`: http://antigrain.com/ +# .. _Postscript: https://en.wikipedia.org/wiki/PostScript +# .. _`Portable Document Format`: https://en.wikipedia.org/wiki/Portable_Document_Format +# .. _`Scalable Vector Graphics`: https://en.wikipedia.org/wiki/Scalable_Vector_Graphics +# .. _`Cairo graphics`: https://en.wikipedia.org/wiki/Cairo_(graphics) +# .. _`Gimp Drawing Kit`: https://en.wikipedia.org/wiki/GDK +# .. _PyGTK: http://www.pygtk.org +# .. _PyGObject: https://wiki.gnome.org/action/show/Projects/PyGObject +# .. _pycairo: https://www.cairographics.org/pycairo/ +# .. _cairocffi: https://pythonhosted.org/cairocffi/ +# .. _wxPython: https://www.wxpython.org/ +# .. _TkInter: https://wiki.python.org/moin/TkInter +# .. _PyQt4: https://riverbankcomputing.com/software/pyqt/intro +# .. _PyQt5: https://riverbankcomputing.com/software/pyqt/intro +# +# WX backends +# =========== +# +# At present the release version of `wxPython` (also known as wxPython classic) +# does not support python3. A work in progress redesigned version known as +# wxPython-Phoenix_ does support python3. +# Matplotlib should work with both versions. +# +# .. _wxPython-Phoenix: https://wxpython.org/Phoenix/docs/html/main.html +# +# GTK and Cairo +# ============= +# +# Both `GTK2` and `GTK3` have implicit dependencies on PyCairo regardless of the +# specific Matplotlib backend used. Unfortunatly the latest release of PyCairo +# for Python3 does not implement the Python wrappers needed for the `GTK3Agg` +# backend. `Cairocffi` can be used as a replacement which implements the correct +# wrapper. +# +# How do I select PyQt4 or PySide? +# ======================================== +# +# You can choose either PyQt4 or PySide when using the `qt4` backend by setting +# the appropriate value for `backend.qt4` in your :file:`matplotlibrc` file. The +# default value is `PyQt4`. +# +# The setting in your :file:`matplotlibrc` file can be overridden by setting the +# `QT_API` environment variable to either `pyqt` or `pyside` to use `PyQt4` or +# `PySide`, respectively. +# +# Since the default value for the bindings to be used is `PyQt4`, +# :mod:`matplotlib` first tries to import it, if the import fails, it tries to +# import `PySide`. +# +# .. _interactive-mode: +# +# What is interactive mode? +# =================================== +# +# Use of an interactive backend (see :ref:`what-is-a-backend`) +# permits--but does not by itself require or ensure--plotting +# to the screen. Whether and when plotting to the screen occurs, +# and whether a script or shell session continues after a plot +# is drawn on the screen, depends on the functions and methods +# that are called, and on a state variable that determines whether +# matplotlib is in "interactive mode". The default Boolean value is set +# by the :file:`matplotlibrc` file, and may be customized like any other +# configuration parameter (see :ref:`sphx_glr_tutorials_01_introductory_customizing.py`). It +# may also be set via :func:`matplotlib.interactive`, and its +# value may be queried via :func:`matplotlib.is_interactive`. Turning +# interactive mode on and off in the middle of a stream of plotting +# commands, whether in a script or in a shell, is rarely needed +# and potentially confusing, so in the following we will assume all +# plotting is done with interactive mode either on or off. +# +# .. note:: +# Major changes related to interactivity, and in particular the +# role and behavior of :func:`~matplotlib.pyplot.show`, were made in the +# transition to matplotlib version 1.0, and bugs were fixed in +# 1.0.1. Here we describe the version 1.0.1 behavior for the +# primary interactive backends, with the partial exception of +# *macosx*. +# +# Interactive mode may also be turned on via :func:`matplotlib.pyplot.ion`, +# and turned off via :func:`matplotlib.pyplot.ioff`. +# +# .. note:: +# Interactive mode works with suitable backends in ipython and in +# the ordinary python shell, but it does *not* work in the IDLE IDE. +# If the default backend does not support interactivity, an interactive +# backend can be explicitly activated using any of the methods discussed in `What is a backend?`_. +# +# +# Interactive example +# -------------------- +# +# From an ordinary python prompt, or after invoking ipython with no options, +# try this:: +# +# import matplotlib.pyplot as plt +# plt.ion() +# plt.plot([1.6, 2.7]) +# +# Assuming you are running version 1.0.1 or higher, and you have +# an interactive backend installed and selected by default, you should +# see a plot, and your terminal prompt should also be active; you +# can type additional commands such as:: +# +# plt.title("interactive test") +# plt.xlabel("index") +# +# and you will see the plot being updated after each line. This is +# because you are in interactive mode *and* you are using pyplot +# functions. Now try an alternative method of modifying the +# plot. Get a reference to the :class:`~matplotlib.axes.Axes` instance, and +# call a method of that instance:: +# +# ax = plt.gca() +# ax.plot([3.1, 2.2]) +# +# Nothing changed, because the Axes methods do not include an +# automatic call to :func:`~matplotlib.pyplot.draw_if_interactive`; +# that call is added by the pyplot functions. If you are using +# methods, then when you want to update the plot on the screen, +# you need to call :func:`~matplotlib.pyplot.draw`:: +# +# plt.draw() +# +# Now you should see the new line added to the plot. +# +# Non-interactive example +# ----------------------- +# +# Start a fresh session as in the previous example, but now +# turn interactive mode off:: +# +# import matplotlib.pyplot as plt +# plt.ioff() +# plt.plot([1.6, 2.7]) +# +# Nothing happened--or at least nothing has shown up on the +# screen (unless you are using *macosx* backend, which is +# anomalous). To make the plot appear, you need to do this:: +# +# plt.show() +# +# Now you see the plot, but your terminal command line is +# unresponsive; the :func:`show()` command *blocks* the input +# of additional commands until you manually kill the plot +# window. +# +# What good is this--being forced to use a blocking function? +# Suppose you need a script that plots the contents of a file +# to the screen. You want to look at that plot, and then end +# the script. Without some blocking command such as show(), the +# script would flash up the plot and then end immediately, +# leaving nothing on the screen. +# +# In addition, non-interactive mode delays all drawing until +# show() is called; this is more efficient than redrawing +# the plot each time a line in the script adds a new feature. +# +# Prior to version 1.0, show() generally could not be called +# more than once in a single script (although sometimes one +# could get away with it); for version 1.0.1 and above, this +# restriction is lifted, so one can write a script like this: + +import numpy as np +import matplotlib.pyplot as plt + +plt.ioff() +for i in range(3): + plt.plot(np.random.rand(10)) + plt.show() + +############################################################################### +# which makes three plots, one at a time. +# +# Summary +# ------- +# +# In interactive mode, pyplot functions automatically draw +# to the screen. +# +# When plotting interactively, if using +# object method calls in addition to pyplot functions, then +# call :func:`~matplotlib.pyplot.draw` whenever you want to +# refresh the plot. +# +# Use non-interactive mode in scripts in which you want to +# generate one or more figures and display them before ending +# or generating a new set of figures. In that case, use +# :func:`~matplotlib.pyplot.show` to display the figure(s) and +# to block execution until you have manually destroyed them. diff --git a/tutorials/02_intermediate/README.txt b/tutorials/02_intermediate/README.txt new file mode 100644 index 000000000000..687c640f5173 --- /dev/null +++ b/tutorials/02_intermediate/README.txt @@ -0,0 +1,8 @@ +.. _tutorials-intermediate: + +Intermediate +============ + +These tutorials cover some of the more complicated classes and functions +in Matplotlib. They can be useful for particular custom and complex +visualizations. diff --git a/tutorials/02_intermediate/artists.py b/tutorials/02_intermediate/artists.py new file mode 100644 index 000000000000..93f6a25bd33d --- /dev/null +++ b/tutorials/02_intermediate/artists.py @@ -0,0 +1,698 @@ +""" +=============== +Artist tutorial +=============== + +Using Artist objects to render on the canvas. + +There are three layers to the matplotlib API. + +* the :class:`matplotlib.backend_bases.FigureCanvas` is the area onto which + the figure is drawn +* the :class:`matplotlib.backend_bases.Renderer` is + the object which knows how to draw on the + :class:`~matplotlib.backend_bases.FigureCanvas` +* and the :class:`matplotlib.artist.Artist` is the object that knows how to use + a renderer to paint onto the canvas. + +The :class:`~matplotlib.backend_bases.FigureCanvas` and +:class:`~matplotlib.backend_bases.Renderer` handle all the details of +talking to user interface toolkits like `wxPython +`_ or drawing languages like PostScript®, and +the ``Artist`` handles all the high level constructs like representing +and laying out the figure, text, and lines. The typical user will +spend 95% of their time working with the ``Artists``. + +There are two types of ``Artists``: primitives and containers. The primitives +represent the standard graphical objects we want to paint onto our canvas: +:class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.patches.Rectangle`, +:class:`~matplotlib.text.Text`, :class:`~matplotlib.image.AxesImage`, etc., and +the containers are places to put them (:class:`~matplotlib.axis.Axis`, +:class:`~matplotlib.axes.Axes` and :class:`~matplotlib.figure.Figure`). The +standard use is to create a :class:`~matplotlib.figure.Figure` instance, use +the ``Figure`` to create one or more :class:`~matplotlib.axes.Axes` or +:class:`~matplotlib.axes.Subplot` instances, and use the ``Axes`` instance +helper methods to create the primitives. In the example below, we create a +``Figure`` instance using :func:`matplotlib.pyplot.figure`, which is a +convenience method for instantiating ``Figure`` instances and connecting them +with your user interface or drawing toolkit ``FigureCanvas``. As we will +discuss below, this is not necessary -- you can work directly with PostScript, +PDF Gtk+, or wxPython ``FigureCanvas`` instances, instantiate your ``Figures`` +directly and connect them yourselves -- but since we are focusing here on the +``Artist`` API we'll let :mod:`~matplotlib.pyplot` handle some of those details +for us:: + + import matplotlib.pyplot as plt + fig = plt.figure() + ax = fig.add_subplot(2,1,1) # two rows, one column, first plot + +The :class:`~matplotlib.axes.Axes` is probably the most important +class in the matplotlib API, and the one you will be working with most +of the time. This is because the ``Axes`` is the plotting area into +which most of the objects go, and the ``Axes`` has many special helper +methods (:meth:`~matplotlib.axes.Axes.plot`, +:meth:`~matplotlib.axes.Axes.text`, +:meth:`~matplotlib.axes.Axes.hist`, +:meth:`~matplotlib.axes.Axes.imshow`) to create the most common +graphics primitives (:class:`~matplotlib.lines.Line2D`, +:class:`~matplotlib.text.Text`, +:class:`~matplotlib.patches.Rectangle`, +:class:`~matplotlib.image.Image`, respectively). These helper methods +will take your data (e.g., ``numpy`` arrays and strings) and create +primitive ``Artist`` instances as needed (e.g., ``Line2D``), add them to +the relevant containers, and draw them when requested. Most of you +are probably familiar with the :class:`~matplotlib.axes.Subplot`, +which is just a special case of an ``Axes`` that lives on a regular +rows by columns grid of ``Subplot`` instances. If you want to create +an ``Axes`` at an arbitrary location, simply use the +:meth:`~matplotlib.figure.Figure.add_axes` method which takes a list +of ``[left, bottom, width, height]`` values in 0-1 relative figure +coordinates:: + + fig2 = plt.figure() + ax2 = fig2.add_axes([0.15, 0.1, 0.7, 0.3]) + +Continuing with our example:: + + import numpy as np + t = np.arange(0.0, 1.0, 0.01) + s = np.sin(2*np.pi*t) + line, = ax.plot(t, s, color='blue', lw=2) + +In this example, ``ax`` is the ``Axes`` instance created by the +``fig.add_subplot`` call above (remember ``Subplot`` is just a +subclass of ``Axes``) and when you call ``ax.plot``, it creates a +``Line2D`` instance and adds it to the :attr:`Axes.lines +` list. In the interactive `ipython +`_ session below, you can see that the +``Axes.lines`` list is length one and contains the same line that was +returned by the ``line, = ax.plot...`` call: + +.. sourcecode:: ipython + + In [101]: ax.lines[0] + Out[101]: + + In [102]: line + Out[102]: + +If you make subsequent calls to ``ax.plot`` (and the hold state is "on" +which is the default) then additional lines will be added to the list. +You can remove lines later simply by calling the list methods; either +of these will work:: + + del ax.lines[0] + ax.lines.remove(line) # one or the other, not both! + +The Axes also has helper methods to configure and decorate the x-axis +and y-axis tick, tick labels and axis labels:: + + xtext = ax.set_xlabel('my xdata') # returns a Text instance + ytext = ax.set_ylabel('my ydata') + +When you call :meth:`ax.set_xlabel `, +it passes the information on the :class:`~matplotlib.text.Text` +instance of the :class:`~matplotlib.axis.XAxis`. Each ``Axes`` +instance contains an :class:`~matplotlib.axis.XAxis` and a +:class:`~matplotlib.axis.YAxis` instance, which handle the layout and +drawing of the ticks, tick labels and axis labels. + +.. I'm commenting this out, since the new Sphinx cross-references +.. sort of take care of this above - MGD + +.. Here are the most important matplotlib modules that contain the +.. classes referenced above + +.. =============== ================== +.. Artist Module +.. =============== ================== +.. Artist matplotlib.artist +.. Rectangle matplotlib.patches +.. Line2D matplotlib.lines +.. Axes matplotlib.axes +.. XAxis and YAxis matplotlib.axis +.. Figure matplotlib.figure +.. Text matplotlib.text +.. =============== ================== + +Try creating the figure below. +""" + +import numpy as np +import matplotlib.pyplot as plt + +fig = plt.figure() +fig.subplots_adjust(top=0.8) +ax1 = fig.add_subplot(211) +ax1.set_ylabel('volts') +ax1.set_title('a sine wave') + +t = np.arange(0.0, 1.0, 0.01) +s = np.sin(2*np.pi*t) +line, = ax1.plot(t, s, color='blue', lw=2) + +# Fixing random state for reproducibility +np.random.seed(19680801) + +ax2 = fig.add_axes([0.15, 0.1, 0.7, 0.3]) +n, bins, patches = ax2.hist(np.random.randn(1000), 50, + facecolor='yellow', edgecolor='yellow') +ax2.set_xlabel('time (s)') + +plt.show() + +############################################################################### +# .. _customizing-artists: +# +# Customizing your objects +# ======================== +# +# Every element in the figure is represented by a matplotlib +# :class:`~matplotlib.artist.Artist`, and each has an extensive list of +# properties to configure its appearance. The figure itself contains a +# :class:`~matplotlib.patches.Rectangle` exactly the size of the figure, +# which you can use to set the background color and transparency of the +# figures. Likewise, each :class:`~matplotlib.axes.Axes` bounding box +# (the standard white box with black edges in the typical matplotlib +# plot, has a ``Rectangle`` instance that determines the color, +# transparency, and other properties of the Axes. These instances are +# stored as member variables :attr:`Figure.patch +# ` and :attr:`Axes.patch +# ` ("Patch" is a name inherited from +# MATLAB, and is a 2D "patch" of color on the figure, e.g., rectangles, +# circles and polygons). Every matplotlib ``Artist`` has the following +# properties +# +# ========== ================================================================================ +# Property Description +# ========== ================================================================================ +# alpha The transparency - a scalar from 0-1 +# animated A boolean that is used to facilitate animated drawing +# axes The axes that the Artist lives in, possibly None +# clip_box The bounding box that clips the Artist +# clip_on Whether clipping is enabled +# clip_path The path the artist is clipped to +# contains A picking function to test whether the artist contains the pick point +# figure The figure instance the artist lives in, possibly None +# label A text label (e.g., for auto-labeling) +# picker A python object that controls object picking +# transform The transformation +# visible A boolean whether the artist should be drawn +# zorder A number which determines the drawing order +# rasterized Boolean; Turns vectors into rastergraphics: (for compression & eps transparency) +# ========== ================================================================================ +# +# Each of the properties is accessed with an old-fashioned setter or +# getter (yes we know this irritates Pythonistas and we plan to support +# direct access via properties or traits but it hasn't been done yet). +# For example, to multiply the current alpha by a half:: +# +# a = o.get_alpha() +# o.set_alpha(0.5*a) +# +# If you want to set a number of properties at once, you can also use +# the ``set`` method with keyword arguments. For example:: +# +# o.set(alpha=0.5, zorder=2) +# +# If you are working interactively at the python shell, a handy way to +# inspect the ``Artist`` properties is to use the +# :func:`matplotlib.artist.getp` function (simply +# :func:`~matplotlib.pylab.getp` in pylab), which lists the properties +# and their values. This works for classes derived from ``Artist`` as +# well, e.g., ``Figure`` and ``Rectangle``. Here are the ``Figure`` rectangle +# properties mentioned above: +# +# .. sourcecode:: ipython +# +# In [149]: matplotlib.artist.getp(fig.patch) +# alpha = 1.0 +# animated = False +# antialiased or aa = True +# axes = None +# clip_box = None +# clip_on = False +# clip_path = None +# contains = None +# edgecolor or ec = w +# facecolor or fc = 0.75 +# figure = Figure(8.125x6.125) +# fill = 1 +# hatch = None +# height = 1 +# label = +# linewidth or lw = 1.0 +# picker = None +# transform = +# verts = ((0, 0), (0, 1), (1, 1), (1, 0)) +# visible = True +# width = 1 +# window_extent = +# x = 0 +# y = 0 +# zorder = 1 +# +# .. TODO: Update these URLs +# +# The docstrings for all of the classes also contain the ``Artist`` +# properties, so you can consult the interactive "help" or the +# :ref:`artist-api` for a listing of properties for a given object. +# +# .. _object-containers: +# +# Object containers +# ================= +# +# +# Now that we know how to inspect and set the properties of a given +# object we want to configure, we need to know how to get at that object. +# As mentioned in the introduction, there are two kinds of objects: +# primitives and containers. The primitives are usually the things you +# want to configure (the font of a :class:`~matplotlib.text.Text` +# instance, the width of a :class:`~matplotlib.lines.Line2D`) although +# the containers also have some properties as well -- for example the +# :class:`~matplotlib.axes.Axes` :class:`~matplotlib.artist.Artist` is a +# container that contains many of the primitives in your plot, but it +# also has properties like the ``xscale`` to control whether the xaxis +# is 'linear' or 'log'. In this section we'll review where the various +# container objects store the ``Artists`` that you want to get at. +# +# .. _figure-container: +# +# Figure container +# ================ +# +# The top level container ``Artist`` is the +# :class:`matplotlib.figure.Figure`, and it contains everything in the +# figure. The background of the figure is a +# :class:`~matplotlib.patches.Rectangle` which is stored in +# :attr:`Figure.patch `. As +# you add subplots (:meth:`~matplotlib.figure.Figure.add_subplot`) and +# axes (:meth:`~matplotlib.figure.Figure.add_axes`) to the figure +# these will be appended to the :attr:`Figure.axes +# `. These are also returned by the +# methods that create them: +# +# .. sourcecode:: ipython +# +# In [156]: fig = plt.figure() +# +# In [157]: ax1 = fig.add_subplot(211) +# +# In [158]: ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3]) +# +# In [159]: ax1 +# Out[159]: +# +# In [160]: print fig.axes +# [, ] +# +# Because the figure maintains the concept of the "current axes" (see +# :meth:`Figure.gca ` and +# :meth:`Figure.sca `) to support the +# pylab/pyplot state machine, you should not insert or remove axes +# directly from the axes list, but rather use the +# :meth:`~matplotlib.figure.Figure.add_subplot` and +# :meth:`~matplotlib.figure.Figure.add_axes` methods to insert, and the +# :meth:`~matplotlib.figure.Figure.delaxes` method to delete. You are +# free however, to iterate over the list of axes or index into it to get +# access to ``Axes`` instances you want to customize. Here is an +# example which turns all the axes grids on:: +# +# for ax in fig.axes: +# ax.grid(True) +# +# +# The figure also has its own text, lines, patches and images, which you +# can use to add primitives directly. The default coordinate system for +# the ``Figure`` will simply be in pixels (which is not usually what you +# want) but you can control this by setting the transform property of +# the ``Artist`` you are adding to the figure. +# +# .. TODO: Is that still true? +# +# More useful is "figure coordinates" where (0, 0) is the bottom-left of +# the figure and (1, 1) is the top-right of the figure which you can +# obtain by setting the ``Artist`` transform to :attr:`fig.transFigure +# `: + +import matplotlib.lines as lines + +fig = plt.figure() + +l1 = lines.Line2D([0, 1], [0, 1], transform=fig.transFigure, figure=fig) +l2 = lines.Line2D([0, 1], [1, 0], transform=fig.transFigure, figure=fig) +fig.lines.extend([l1, l2]) + +plt.show() + +############################################################################### +# Here is a summary of the Artists the figure contains +# +# .. TODO: Add xrefs to this table +# +# ================ =============================================================== +# Figure attribute Description +# ================ =============================================================== +# axes A list of Axes instances (includes Subplot) +# patch The Rectangle background +# images A list of FigureImages patches - useful for raw pixel display +# legends A list of Figure Legend instances (different from Axes.legends) +# lines A list of Figure Line2D instances (rarely used, see Axes.lines) +# patches A list of Figure patches (rarely used, see Axes.patches) +# texts A list Figure Text instances +# ================ =============================================================== +# +# .. _axes-container: +# +# Axes container +# ============== +# +# The :class:`matplotlib.axes.Axes` is the center of the matplotlib +# universe -- it contains the vast majority of all the ``Artists`` used +# in a figure with many helper methods to create and add these +# ``Artists`` to itself, as well as helper methods to access and +# customize the ``Artists`` it contains. Like the +# :class:`~matplotlib.figure.Figure`, it contains a +# :class:`~matplotlib.patches.Patch` +# :attr:`~matplotlib.axes.Axes.patch` which is a +# :class:`~matplotlib.patches.Rectangle` for Cartesian coordinates and a +# :class:`~matplotlib.patches.Circle` for polar coordinates; this patch +# determines the shape, background and border of the plotting region:: +# +# ax = fig.add_subplot(111) +# rect = ax.patch # a Rectangle instance +# rect.set_facecolor('green') +# +# When you call a plotting method, e.g., the canonical +# :meth:`~matplotlib.axes.Axes.plot` and pass in arrays or lists of +# values, the method will create a :meth:`matplotlib.lines.Line2D` +# instance, update the line with all the ``Line2D`` properties passed as +# keyword arguments, add the line to the :attr:`Axes.lines +# ` container, and returns it to you: +# +# .. sourcecode:: ipython +# +# In [213]: x, y = np.random.rand(2, 100) +# +# In [214]: line, = ax.plot(x, y, '-', color='blue', linewidth=2) +# +# ``plot`` returns a list of lines because you can pass in multiple x, y +# pairs to plot, and we are unpacking the first element of the length +# one list into the line variable. The line has been added to the +# ``Axes.lines`` list: +# +# .. sourcecode:: ipython +# +# In [229]: print ax.lines +# [] +# +# Similarly, methods that create patches, like +# :meth:`~matplotlib.axes.Axes.bar` creates a list of rectangles, will +# add the patches to the :attr:`Axes.patches +# ` list: +# +# .. sourcecode:: ipython +# +# In [233]: n, bins, rectangles = ax.hist(np.random.randn(1000), 50, facecolor='yellow') +# +# In [234]: rectangles +# Out[234]: +# +# In [235]: print len(ax.patches) +# +# You should not add objects directly to the ``Axes.lines`` or +# ``Axes.patches`` lists unless you know exactly what you are doing, +# because the ``Axes`` needs to do a few things when it creates and adds +# an object. It sets the figure and axes property of the ``Artist``, as +# well as the default ``Axes`` transformation (unless a transformation +# is set). It also inspects the data contained in the ``Artist`` to +# update the data structures controlling auto-scaling, so that the view +# limits can be adjusted to contain the plotted data. You can, +# nonetheless, create objects yourself and add them directly to the +# ``Axes`` using helper methods like +# :meth:`~matplotlib.axes.Axes.add_line` and +# :meth:`~matplotlib.axes.Axes.add_patch`. Here is an annotated +# interactive session illustrating what is going on: +# +# .. sourcecode:: ipython +# +# In [261]: fig = plt.figure() +# +# In [262]: ax = fig.add_subplot(111) +# +# # create a rectangle instance +# In [263]: rect = matplotlib.patches.Rectangle( (1,1), width=5, height=12) +# +# # by default the axes instance is None +# In [264]: print rect.get_axes() +# None +# +# # and the transformation instance is set to the "identity transform" +# In [265]: print rect.get_transform() +# +# +# # now we add the Rectangle to the Axes +# In [266]: ax.add_patch(rect) +# +# # and notice that the ax.add_patch method has set the axes +# # instance +# In [267]: print rect.get_axes() +# Axes(0.125,0.1;0.775x0.8) +# +# # and the transformation has been set too +# In [268]: print rect.get_transform() +# +# +# # the default axes transformation is ax.transData +# In [269]: print ax.transData +# +# +# # notice that the xlimits of the Axes have not been changed +# In [270]: print ax.get_xlim() +# (0.0, 1.0) +# +# # but the data limits have been updated to encompass the rectangle +# In [271]: print ax.dataLim.bounds +# (1.0, 1.0, 5.0, 12.0) +# +# # we can manually invoke the auto-scaling machinery +# In [272]: ax.autoscale_view() +# +# # and now the xlim are updated to encompass the rectangle +# In [273]: print ax.get_xlim() +# (1.0, 6.0) +# +# # we have to manually force a figure draw +# In [274]: ax.figure.canvas.draw() +# +# +# There are many, many ``Axes`` helper methods for creating primitive +# ``Artists`` and adding them to their respective containers. The table +# below summarizes a small sampling of them, the kinds of ``Artist`` they +# create, and where they store them +# +# ============================== ==================== ======================= +# Helper method Artist Container +# ============================== ==================== ======================= +# ax.annotate - text annotations Annotate ax.texts +# ax.bar - bar charts Rectangle ax.patches +# ax.errorbar - error bar plots Line2D and Rectangle ax.lines and ax.patches +# ax.fill - shared area Polygon ax.patches +# ax.hist - histograms Rectangle ax.patches +# ax.imshow - image data AxesImage ax.images +# ax.legend - axes legends Legend ax.legends +# ax.plot - xy plots Line2D ax.lines +# ax.scatter - scatter charts PolygonCollection ax.collections +# ax.text - text Text ax.texts +# ============================== ==================== ======================= +# +# +# In addition to all of these ``Artists``, the ``Axes`` contains two +# important ``Artist`` containers: the :class:`~matplotlib.axis.XAxis` +# and :class:`~matplotlib.axis.YAxis`, which handle the drawing of the +# ticks and labels. These are stored as instance variables +# :attr:`~matplotlib.axes.Axes.xaxis` and +# :attr:`~matplotlib.axes.Axes.yaxis`. The ``XAxis`` and ``YAxis`` +# containers will be detailed below, but note that the ``Axes`` contains +# many helper methods which forward calls on to the +# :class:`~matplotlib.axis.Axis` instances so you often do not need to +# work with them directly unless you want to. For example, you can set +# the font color of the ``XAxis`` ticklabels using the ``Axes`` helper +# method:: +# +# for label in ax.get_xticklabels(): +# label.set_color('orange') +# +# Below is a summary of the Artists that the Axes contains +# +# ============== ====================================== +# Axes attribute Description +# ============== ====================================== +# artists A list of Artist instances +# patch Rectangle instance for Axes background +# collections A list of Collection instances +# images A list of AxesImage +# legends A list of Legend instances +# lines A list of Line2D instances +# patches A list of Patch instances +# texts A list of Text instances +# xaxis matplotlib.axis.XAxis instance +# yaxis matplotlib.axis.YAxis instance +# ============== ====================================== +# +# .. _axis-container: +# +# Axis containers +# =============== +# +# The :class:`matplotlib.axis.Axis` instances handle the drawing of the +# tick lines, the grid lines, the tick labels and the axis label. You +# can configure the left and right ticks separately for the y-axis, and +# the upper and lower ticks separately for the x-axis. The ``Axis`` +# also stores the data and view intervals used in auto-scaling, panning +# and zooming, as well as the :class:`~matplotlib.ticker.Locator` and +# :class:`~matplotlib.ticker.Formatter` instances which control where +# the ticks are placed and how they are represented as strings. +# +# Each ``Axis`` object contains a :attr:`~matplotlib.axis.Axis.label` attribute +# (this is what :mod:`~matplotlib.pylab` modifies in calls to +# :func:`~matplotlib.pylab.xlabel` and :func:`~matplotlib.pylab.ylabel`) as well +# as a list of major and minor ticks. The ticks are +# :class:`~matplotlib.axis.XTick` and :class:`~matplotlib.axis.YTick` instances, +# which contain the actual line and text primitives that render the ticks and +# ticklabels. Because the ticks are dynamically created as needed (e.g., when +# panning and zooming), you should access the lists of major and minor ticks +# through their accessor methods :meth:`~matplotlib.axis.Axis.get_major_ticks` +# and :meth:`~matplotlib.axis.Axis.get_minor_ticks`. Although the ticks contain +# all the primitives and will be covered below, ``Axis`` instances have accessor +# methods that return the tick lines, tick labels, tick locations etc.: + +fig, ax = plt.subplots() +axis = ax.xaxis +axis.get_ticklocs() + +############################################################################### + +axis.get_ticklabels() + +############################################################################### +# note there are twice as many ticklines as labels because by +# default there are tick lines at the top and bottom but only tick +# labels below the xaxis; this can be customized + +axis.get_ticklines() + +############################################################################### +# by default you get the major ticks back + +axis.get_ticklines() + +############################################################################### +# but you can also ask for the minor ticks + +axis.get_ticklines(minor=True) + +# Here is a summary of some of the useful accessor methods of the ``Axis`` +# (these have corresponding setters where useful, such as +# set_major_formatter) +# +# ====================== ========================================================= +# Accessor method Description +# ====================== ========================================================= +# get_scale The scale of the axis, e.g., 'log' or 'linear' +# get_view_interval The interval instance of the axis view limits +# get_data_interval The interval instance of the axis data limits +# get_gridlines A list of grid lines for the Axis +# get_label The axis label - a Text instance +# get_ticklabels A list of Text instances - keyword minor=True|False +# get_ticklines A list of Line2D instances - keyword minor=True|False +# get_ticklocs A list of Tick locations - keyword minor=True|False +# get_major_locator The matplotlib.ticker.Locator instance for major ticks +# get_major_formatter The matplotlib.ticker.Formatter instance for major ticks +# get_minor_locator The matplotlib.ticker.Locator instance for minor ticks +# get_minor_formatter The matplotlib.ticker.Formatter instance for minor ticks +# get_major_ticks A list of Tick instances for major ticks +# get_minor_ticks A list of Tick instances for minor ticks +# grid Turn the grid on or off for the major or minor ticks +# ====================== ========================================================= +# +# Here is an example, not recommended for its beauty, which customizes +# the axes and tick properties + +# plt.figure creates a matplotlib.figure.Figure instance +fig = plt.figure() +rect = fig.patch # a rectangle instance +rect.set_facecolor('lightgoldenrodyellow') + +ax1 = fig.add_axes([0.1, 0.3, 0.4, 0.4]) +rect = ax1.patch +rect.set_facecolor('lightslategray') + + +for label in ax1.xaxis.get_ticklabels(): + # label is a Text instance + label.set_color('red') + label.set_rotation(45) + label.set_fontsize(16) + +for line in ax1.yaxis.get_ticklines(): + # line is a Line2D instance + line.set_color('green') + line.set_markersize(25) + line.set_markeredgewidth(3) + +plt.show() + +############################################################################### +# .. _tick-container: +# +# Tick containers +# =============== +# +# The :class:`matplotlib.axis.Tick` is the final container object in our +# descent from the :class:`~matplotlib.figure.Figure` to the +# :class:`~matplotlib.axes.Axes` to the :class:`~matplotlib.axis.Axis` +# to the :class:`~matplotlib.axis.Tick`. The ``Tick`` contains the tick +# and grid line instances, as well as the label instances for the upper +# and lower ticks. Each of these is accessible directly as an attribute +# of the ``Tick``. In addition, there are boolean variables that determine +# whether the upper labels and ticks are on for the x-axis and whether +# the right labels and ticks are on for the y-axis. +# +# ============== ========================================================== +# Tick attribute Description +# ============== ========================================================== +# tick1line Line2D instance +# tick2line Line2D instance +# gridline Line2D instance +# label1 Text instance +# label2 Text instance +# gridOn boolean which determines whether to draw the gridline +# tick1On boolean which determines whether to draw the 1st tickline +# tick2On boolean which determines whether to draw the 2nd tickline +# label1On boolean which determines whether to draw the 1st tick label +# label2On boolean which determines whether to draw the 2nd tick label +# ============== ========================================================== +# +# Here is an example which sets the formatter for the right side ticks with +# dollar signs and colors them green on the right side of the yaxis + +import matplotlib.ticker as ticker + +# Fixing random state for reproducibility +np.random.seed(19680801) + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.plot(100*np.random.rand(20)) + +formatter = ticker.FormatStrFormatter('$%1.2f') +ax.yaxis.set_major_formatter(formatter) + +for tick in ax.yaxis.get_major_ticks(): + tick.label1On = False + tick.label2On = True + tick.label2.set_color('green') + +plt.show() diff --git a/tutorials/02_intermediate/gridspec.py b/tutorials/02_intermediate/gridspec.py new file mode 100644 index 000000000000..e604e05e5874 --- /dev/null +++ b/tutorials/02_intermediate/gridspec.py @@ -0,0 +1,203 @@ +""" +============================================== +Customizing Location of Subplot Using GridSpec +============================================== + +How to create grid-shaped combinations of axes. + + :class:`~matplotlib.gridspec.GridSpec` + specifies the geometry of the grid that a subplot will be + placed. The number of rows and number of columns of the grid + need to be set. Optionally, the subplot layout parameters + (e.g., left, right, etc.) can be tuned. + + :class:`~matplotlib.gridspec.SubplotSpec` + specifies the location of the subplot in the given *GridSpec*. + + :func:`~matplotlib.pyplot.subplot2grid` + a helper function that is similar to :func:`~matplotlib.pyplot.subplot` + but uses 0-based indexing and let subplot to occupy multiple cells. +""" +import matplotlib.pyplot as plt +import matplotlib.gridspec as gridspec + +############################################################################### +# Basic Example of using subplot2grid +# =================================== + +# To use :func:`~matplotlib.pyplot.subplot2grid`, you provide geometry of +# the grid and the location of the subplot in the grid. For a simple +# single-cell subplot + +fig = plt.figure() +ax = plt.subplot2grid((2, 2), (0, 0)) + +# is identical to + +fig = plt.figure() +ax = plt.subplot(2, 2, 1) + +############################################################################### +# Note that, unlike Matplotlib's subplot, the index starts from 0 in GridSpec. +# +# To create a subplot that spans multiple cells: + +fig = plt.figure() +ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2) +ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) + +############################################################################### +# For example, see the output of the following commands: + +ax1 = plt.subplot2grid((3, 3), (0, 0), colspan=3) +ax2 = plt.subplot2grid((3, 3), (1, 0), colspan=2) +ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) +ax4 = plt.subplot2grid((3, 3), (2, 0)) +ax5 = plt.subplot2grid((3, 3), (2, 1)) + +############################################################################### +# GridSpec and SubplotSpec +# ======================== +# +# You can create :class:`~matplotlib.gridspec.GridSpec` explicitly and use +# them to create a subplot. +# +# For example: + +fig = plt.figure() +ax = plt.subplot2grid((2, 2), (0, 0)) + +# is equal to: + +fig = plt.figure() +gs = gridspec.GridSpec(2, 2) +ax = plt.subplot(gs[0, 0]) + +# A GridSpec instance provides array-like (2d or 1d) indexing that +# returns the SubplotSpec instance. For a SubplotSpec that spans multiple +# cells, use slice. :: + +ax2 = plt.subplot(gs[1, :-1]) +ax3 = plt.subplot(gs[1:, -1]) + +############################################################################### +# The above example becomes :: + +fig = plt.figure() +gs = gridspec.GridSpec(3, 3) +ax1 = plt.subplot(gs[0, :]) +ax2 = plt.subplot(gs[1, :-1]) +ax3 = plt.subplot(gs[1:, -1]) +ax4 = plt.subplot(gs[-1, 0]) +ax5 = plt.subplot(gs[-1, -2]) + +############################################################################### +# Adjust GridSpec layout +# ====================== +# +# When a GridSpec is explicitly used, you can adjust the layout +# parameters of subplots that are created from the GridSpec. :: + +fig = plt.figure() +gs1 = gridspec.GridSpec(3, 3) +gs1.update(left=0.05, right=0.48, wspace=0.05) + +############################################################################### +# This is similar to :func:`~matplotlib.pyplot.subplots_adjust`, but it only +# affects the subplots that are created from the given GridSpec. +# +# For example, see this code and the resulting figure: + +fig = plt.figure() +gs1 = gridspec.GridSpec(3, 3) +gs1.update(left=0.05, right=0.48, wspace=0.05) +ax1 = plt.subplot(gs1[:-1, :]) +ax2 = plt.subplot(gs1[-1, :-1]) +ax3 = plt.subplot(gs1[-1, -1]) + +fig = plt.figure() +gs2 = gridspec.GridSpec(3, 3) +gs2.update(left=0.55, right=0.98, hspace=0.05) +ax4 = plt.subplot(gs2[:, :-1]) +ax5 = plt.subplot(gs2[:-1, -1]) +ax6 = plt.subplot(gs2[-1, -1]) + +############################################################################### +# GridSpec using SubplotSpec +# ========================== +# +# You can create GridSpec from the :class:`~matplotlib.gridspec.SubplotSpec`, +# in which case its layout parameters are set to that of the location of +# the given SubplotSpec. + +fig = plt.figure() +gs0 = gridspec.GridSpec(1, 2) + +gs00 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[0]) +gs01 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[1]) + +############################################################################### +# A Complex Nested GridSpec using SubplotSpec +# =========================================== +# +# Here's a more sophisticated example of nested GridSpec where we put +# a box around each cell of the outer 4x4 grid, by hiding appropriate +# spines in each of the inner 3x3 grids. + +import numpy as np +from itertools import product + + +def squiggle_xy(a, b, c, d, i=np.arange(0.0, 2*np.pi, 0.05)): + return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d) + +fig = plt.figure(figsize=(8, 8)) + +# gridspec inside gridspec +outer_grid = gridspec.GridSpec(4, 4, wspace=0.0, hspace=0.0) + +for i in range(16): + inner_grid = gridspec.GridSpecFromSubplotSpec( + 3, 3, subplot_spec=outer_grid[i], wspace=0.0, hspace=0.0) + a, b = int(i/4)+1, i % 4+1 + for j, (c, d) in enumerate(product(range(1, 4), repeat=2)): + ax = plt.Subplot(fig, inner_grid[j]) + ax.plot(*squiggle_xy(a, b, c, d)) + ax.set_xticks([]) + ax.set_yticks([]) + fig.add_subplot(ax) + +all_axes = fig.get_axes() + +# show only the outside spines +for ax in all_axes: + for sp in ax.spines.values(): + sp.set_visible(False) + if ax.is_first_row(): + ax.spines['top'].set_visible(True) + if ax.is_last_row(): + ax.spines['bottom'].set_visible(True) + if ax.is_first_col(): + ax.spines['left'].set_visible(True) + if ax.is_last_col(): + ax.spines['right'].set_visible(True) + +plt.show() + +# GridSpec with Varying Cell Sizes +# ================================ +# +# By default, GridSpec creates cells of equal sizes. You can adjust +# relative heights and widths of rows and columns. Note that absolute +# values are meaningless, only their relative ratios matter. + +fig = plt.figure() +gs = gridspec.GridSpec(2, 2, + width_ratios=[1, 2], + height_ratios=[4, 1] + ) + +ax1 = plt.subplot(gs[0]) +ax2 = plt.subplot(gs[1]) +ax3 = plt.subplot(gs[2]) +ax4 = plt.subplot(gs[3]) diff --git a/tutorials/02_intermediate/legend_guide.py b/tutorials/02_intermediate/legend_guide.py new file mode 100644 index 000000000000..40b56bd4817b --- /dev/null +++ b/tutorials/02_intermediate/legend_guide.py @@ -0,0 +1,286 @@ +""" +============ +Legend guide +============ + +Generating legends flexibly in Matplotlib. + +.. currentmodule:: matplotlib.pyplot + +This legend guide is an extension of the documentation available at +:func:`~matplotlib.pyplot.legend` - please ensure you are familiar with +contents of that documentation before proceeding with this guide. + + +This guide makes use of some common terms, which are documented here for clarity: + +.. glossary:: + + legend entry + A legend is made up of one or more legend entries. An entry is made up of + exactly one key and one label. + + legend key + The colored/patterned marker to the left of each legend label. + + legend label + The text which describes the handle represented by the key. + + legend handle + The original object which is used to generate an appropriate entry in + the legend. + + +Controlling the legend entries +============================== + +Calling :func:`legend` with no arguments automatically fetches the legend +handles and their associated labels. This functionality is equivalent to:: + + handles, labels = ax.get_legend_handles_labels() + ax.legend(handles, labels) + +The :meth:`~matplotlib.axes.Axes.get_legend_handles_labels` function returns +a list of handles/artists which exist on the Axes which can be used to +generate entries for the resulting legend - it is worth noting however that +not all artists can be added to a legend, at which point a "proxy" will have +to be created (see :ref:`proxy_legend_handles` for further details). + +# For full control of what is being added to the legend, it is common to pass +# the appropriate handles directly to :func:`legend` + + line_up, = plt.plot([1,2,3], label='Line 2') + line_down, = plt.plot([3,2,1], label='Line 1') + plt.legend(handles=[line_up, line_down]) + +In some cases, it is not possible to set the label of the handle, so it is +possible to pass through the list of labels to :func:`legend`:: + + line_up, = plt.plot([1,2,3], label='Line 2') + line_down, = plt.plot([3,2,1], label='Line 1') + plt.legend([line_up, line_down], ['Line Up', 'Line Down']) + + +.. _proxy_legend_handles: + +Creating artists specifically for adding to the legend (aka. Proxy artists) +=========================================================================== + +Not all handles can be turned into legend entries automatically, +so it is often necessary to create an artist which *can*. Legend handles +don't have to exists on the Figure or Axes in order to be used. + +Suppose we wanted to create a legend which has an entry for some data which +is represented by a red color: +""" + +import matplotlib.patches as mpatches +import matplotlib.pyplot as plt + +red_patch = mpatches.Patch(color='red', label='The red data') +plt.legend(handles=[red_patch]) + +plt.show() + +############################################################################### +# There are many supported legend handles, instead of creating a patch of color +# we could have created a line with a marker: + +import matplotlib.lines as mlines + +blue_line = mlines.Line2D([], [], color='blue', marker='*', + markersize=15, label='Blue stars') +plt.legend(handles=[blue_line]) + +plt.show() + +############################################################################### +# Legend location +# =============== +# +# The location of the legend can be specified by the keyword argument +# *loc*. Please see the documentation at :func:`legend` for more details. +# +# The ``bbox_to_anchor`` keyword gives a great degree of control for manual +# legend placement. For example, if you want your axes legend located at the +# figure's top right-hand corner instead of the axes' corner, simply specify +# the corner's location, and the coordinate system of that location:: +# +# plt.legend(bbox_to_anchor=(1, 1), +# bbox_transform=plt.gcf().transFigure) +# +# More examples of custom legend placement: + +plt.subplot(211) +plt.plot([1, 2, 3], label="test1") +plt.plot([3, 2, 1], label="test2") + +# Place a legend above this subplot, expanding itself to +# fully use the given bounding box. +plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, + ncol=2, mode="expand", borderaxespad=0.) + +plt.subplot(223) +plt.plot([1, 2, 3], label="test1") +plt.plot([3, 2, 1], label="test2") +# Place a legend to the right of this smaller subplot. +plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) + +plt.show() + +############################################################################### +# Multiple legends on the same Axes +# ================================= +# +# Sometimes it is more clear to split legend entries across multiple +# legends. Whilst the instinctive approach to doing this might be to call +# the :func:`legend` function multiple times, you will find that only one +# legend ever exists on the Axes. This has been done so that it is possible +# to call :func:`legend` repeatedly to update the legend to the latest +# handles on the Axes, so to persist old legend instances, we must add them +# manually to the Axes: + +line1, = plt.plot([1, 2, 3], label="Line 1", linestyle='--') +line2, = plt.plot([3, 2, 1], label="Line 2", linewidth=4) + +# Create a legend for the first line. +first_legend = plt.legend(handles=[line1], loc=1) + +# Add the legend manually to the current Axes. +ax = plt.gca().add_artist(first_legend) + +# Create another legend for the second line. +plt.legend(handles=[line2], loc=4) + +plt.show() + +############################################################################### +# Legend Handlers +# =============== +# +# In order to create legend entries, handles are given as an argument to an +# appropriate :class:`~matplotlib.legend_handler.HandlerBase` subclass. +# The choice of handler subclass is determined by the following rules: +# +# 1. Update :func:`~matplotlib.legend.Legend.get_legend_handler_map` +# with the value in the ``handler_map`` keyword. +# 2. Check if the ``handle`` is in the newly created ``handler_map``. +# 3. Check if the type of ``handle`` is in the newly created +# ``handler_map``. +# 4. Check if any of the types in the ``handle``'s mro is in the newly +# created ``handler_map``. +# +# For completeness, this logic is mostly implemented in +# :func:`~matplotlib.legend.Legend.get_legend_handler`. +# +# All of this flexibility means that we have the necessary hooks to implement +# custom handlers for our own type of legend key. +# +# The simplest example of using custom handlers is to instantiate one of the +# existing :class:`~matplotlib.legend_handler.HandlerBase` subclasses. For the +# sake of simplicity, let's choose :class:`matplotlib.legend_handler.HandlerLine2D` +# which accepts a ``numpoints`` argument (note numpoints is a keyword +# on the :func:`legend` function for convenience). We can then pass the mapping +# of instance to Handler as a keyword to legend. + +from matplotlib.legend_handler import HandlerLine2D + +line1, = plt.plot([3, 2, 1], marker='o', label='Line 1') +line2, = plt.plot([1, 2, 3], marker='o', label='Line 2') + +plt.legend(handler_map={line1: HandlerLine2D(numpoints=4)}) + +############################################################################### +# As you can see, "Line 1" now has 4 marker points, where "Line 2" has 2 (the +# default). Try the above code, only change the map's key from ``line1`` to +# ``type(line1)``. Notice how now both :class:`~matplotlib.lines.Line2D` instances +# get 4 markers. +# +# Along with handlers for complex plot types such as errorbars, stem plots +# and histograms, the default ``handler_map`` has a special ``tuple`` handler +# (:class:`~matplotlib.legend_handler.HandlerTuple`) which simply plots +# the handles on top of one another for each item in the given tuple. The +# following example demonstrates combining two legend keys on top of one another: + +from numpy.random import randn + +z = randn(10) + +red_dot, = plt.plot(z, "ro", markersize=15) +# Put a white cross over some of the data. +white_cross, = plt.plot(z[:5], "w+", markeredgewidth=3, markersize=15) + +plt.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"]) + +############################################################################### +# The :class:`~matplotlib.legend_handler.HandlerTuple` class can also be used to +# assign several legend keys to the same entry: + +from matplotlib.legend_handler import HandlerLine2D, HandlerTuple + +p1, = plt.plot([1, 2.5, 3], 'r-d') +p2, = plt.plot([3, 2, 1], 'k-o') + +l = plt.legend([(p1, p2)], ['Two keys'], numpoints=1, + handler_map={tuple: HandlerTuple(ndivide=None)}) + +############################################################################### +# Implementing a custom legend handler +# ------------------------------------ +# +# A custom handler can be implemented to turn any handle into a legend key (handles +# don't necessarily need to be matplotlib artists). +# The handler must implement a "legend_artist" method which returns a +# single artist for the legend to use. Signature details about the "legend_artist" +# are documented at :meth:`~matplotlib.legend_handler.HandlerBase.legend_artist`. + +import matplotlib.patches as mpatches + +class AnyObject(object): + pass + +class AnyObjectHandler(object): + def legend_artist(self, legend, orig_handle, fontsize, handlebox): + x0, y0 = handlebox.xdescent, handlebox.ydescent + width, height = handlebox.width, handlebox.height + patch = mpatches.Rectangle([x0, y0], width, height, facecolor='red', + edgecolor='black', hatch='xx', lw=3, + transform=handlebox.get_transform()) + handlebox.add_artist(patch) + return patch + +plt.legend([AnyObject()], ['My first handler'], + handler_map={AnyObject: AnyObjectHandler()}) + +############################################################################### +# Alternatively, had we wanted to globally accept ``AnyObject`` instances without +# needing to manually set the ``handler_map`` keyword all the time, we could have +# registered the new handler with:: +# +# from matplotlib.legend import Legend +# Legend.update_default_handler_map({AnyObject: AnyObjectHandler()}) +# +# Whilst the power here is clear, remember that there are already many handlers +# implemented and what you want to achieve may already be easily possible with +# existing classes. For example, to produce elliptical legend keys, rather than +# rectangular ones: + +from matplotlib.legend_handler import HandlerPatch + +class HandlerEllipse(HandlerPatch): + def create_artists(self, legend, orig_handle, + xdescent, ydescent, width, height, fontsize, trans): + center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent + p = mpatches.Ellipse(xy=center, width=width + xdescent, + height=height + ydescent) + self.update_prop(p, orig_handle, legend) + p.set_transform(trans) + return [p] + + +c = mpatches.Circle((0.5, 0.5), 0.25, facecolor="green", + edgecolor="red", linewidth=3) +plt.gca().add_patch(c) + +plt.legend([c], ["An ellipse, not a rectangle"], + handler_map={mpatches.Circle: HandlerEllipse()}) diff --git a/tutorials/02_intermediate/tight_layout_guide.py b/tutorials/02_intermediate/tight_layout_guide.py new file mode 100644 index 000000000000..e99afbb40838 --- /dev/null +++ b/tutorials/02_intermediate/tight_layout_guide.py @@ -0,0 +1,329 @@ +""" +================== +Tight Layout guide +================== + +How to use tight-layout to fit plots within your figure cleanly. + +*tight_layout* automatically adjusts subplot params so that the +subplot(s) fits in to the figure area. This is an experimental +feature and may not work for some cases. It only checks the extents +of ticklabels, axis labels, and titles. + + +Simple Example +============== + +In matplotlib, the location of axes (including subplots) are specified in +normalized figure coordinates. It can happen that your axis labels or +titles (or sometimes even ticklabels) go outside the figure area, and are thus +clipped. + +""" + +import matplotlib.pyplot as plt +import numpy as np + +plt.rcParams['savefig.facecolor'] = "0.8" + + +def example_plot(ax, fontsize=12): + ax.plot([1, 2]) + + ax.locator_params(nbins=3) + ax.set_xlabel('x-label', fontsize=fontsize) + ax.set_ylabel('y-label', fontsize=fontsize) + ax.set_title('Title', fontsize=fontsize) + +plt.close('all') +fig, ax = plt.subplots() +example_plot(ax, fontsize=24) + +############################################################################### +# To prevent this, the location of axes needs to be adjusted. For +# subplots, this can be done by adjusting the subplot params +# (:ref:`howto-subplots-adjust`). Matplotlib v1.1 introduces a new +# command :func:`~matplotlib.pyplot.tight_layout` that does this +# automatically for you. + +fig, ax = plt.subplots() +example_plot(ax, fontsize=24) +plt.tight_layout() + +############################################################################### +# When you have multiple subplots, often you see labels of different +# axes overlapping each other. + +plt.close('all') + +fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2) +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +example_plot(ax4) + +############################################################################### +# :func:`~matplotlib.pyplot.tight_layout` will also adjust spacing between +# subplots to minimize the overlaps. + +fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2) +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +example_plot(ax4) +plt.tight_layout() + +############################################################################### +# :func:`~matplotlib.pyplot.tight_layout` can take keyword arguments of +# *pad*, *w_pad* and *h_pad*. These control the extra padding around the +# figure border and between subplots. The pads are specified in fraction +# of fontsize. + +fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2) +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +example_plot(ax4) +plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0) + +############################################################################### +# :func:`~matplotlib.pyplot.tight_layout` will work even if the sizes of +# subplots are different as far as their grid specification is +# compatible. In the example below, *ax1* and *ax2* are subplots of a 2x2 +# grid, while *ax3* is of a 1x2 grid. + +plt.close('all') +fig = plt.figure() + +ax1 = plt.subplot(221) +ax2 = plt.subplot(223) +ax3 = plt.subplot(122) + +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) + +plt.tight_layout() + +############################################################################### +# It works with subplots created with +# :func:`~matplotlib.pyplot.subplot2grid`. In general, subplots created +# from the gridspec (:ref:`sphx_glr_tutorials_02_intermediate_gridspec.py`) will work. + +plt.close('all') +fig = plt.figure() + +ax1 = plt.subplot2grid((3, 3), (0, 0)) +ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2) +ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2) +ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) + +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +example_plot(ax4) + +plt.tight_layout() + +############################################################################### +# Although not thoroughly tested, it seems to work for subplots with +# aspect != "auto" (e.g., axes with images). + +arr = np.arange(100).reshape((10, 10)) + +plt.close('all') +fig = plt.figure(figsize=(5, 4)) + +ax = plt.subplot(111) +im = ax.imshow(arr, interpolation="none") + +plt.tight_layout() + +############################################################################### +# Caveats +# ------- +# +# * :func:`~matplotlib.pyplot.tight_layout` only considers ticklabels, axis +# labels, and titles. Thus, other artists may be clipped and also may +# overlap. +# +# * It assumes that the extra space needed for ticklabels, axis labels, +# and titles is independent of original location of axes. This is +# often true, but there are rare cases where it is not. +# +# * pad=0 clips some of the texts by a few pixels. This may be a bug or +# a limitation of the current algorithm and it is not clear why it +# happens. Meanwhile, use of pad at least larger than 0.3 is +# recommended. +# +# Use with GridSpec +# ----------------- +# +# GridSpec has its own :func:`~matplotlib.gridspec.GridSpec.tight_layout` method +# (the pyplot api :func:`~matplotlib.pyplot.tight_layout` also works). + +import matplotlib.gridspec as gridspec + +plt.close('all') +fig = plt.figure() + +gs1 = gridspec.GridSpec(2, 1) +ax1 = fig.add_subplot(gs1[0]) +ax2 = fig.add_subplot(gs1[1]) + +example_plot(ax1) +example_plot(ax2) + +gs1.tight_layout(fig) + +############################################################################### +# You may provide an optional *rect* parameter, which specifies the bounding box +# that the subplots will be fit inside. The coordinates must be in normalized +# figure coordinates and the default is (0, 0, 1, 1). + +fig = plt.figure() + +gs1 = gridspec.GridSpec(2, 1) +ax1 = fig.add_subplot(gs1[0]) +ax2 = fig.add_subplot(gs1[1]) + +example_plot(ax1) +example_plot(ax2) + +gs1.tight_layout(fig, rect=[0, 0, 0.5, 1]) + +############################################################################### +# For example, this can be used for a figure with multiple gridspecs. + +fig = plt.figure() + +gs1 = gridspec.GridSpec(2, 1) +ax1 = fig.add_subplot(gs1[0]) +ax2 = fig.add_subplot(gs1[1]) + +example_plot(ax1) +example_plot(ax2) + +gs1.tight_layout(fig, rect=[0, 0, 0.5, 1]) + +gs2 = gridspec.GridSpec(3, 1) + +for ss in gs2: + ax = fig.add_subplot(ss) + example_plot(ax) + ax.set_title("") + ax.set_xlabel("") + +ax.set_xlabel("x-label", fontsize=12) + +gs2.tight_layout(fig, rect=[0.5, 0, 1, 1], h_pad=0.5) + +# We may try to match the top and bottom of two grids :: +top = min(gs1.top, gs2.top) +bottom = max(gs1.bottom, gs2.bottom) + +gs1.update(top=top, bottom=bottom) +gs2.update(top=top, bottom=bottom) +plt.show() + +############################################################################### +# While this should be mostly good enough, adjusting top and bottom +# may require adjustment of hspace also. To update hspace & vspace, we +# call :func:`~matplotlib.gridspec.GridSpec.tight_layout` again with updated +# rect argument. Note that the rect argument specifies the area including the +# ticklabels, etc. Thus, we will increase the bottom (which is 0 for the normal +# case) by the difference between the *bottom* from above and the bottom of each +# gridspec. Same thing for the top. + +fig = plt.gcf() + +gs1 = gridspec.GridSpec(2, 1) +ax1 = fig.add_subplot(gs1[0]) +ax2 = fig.add_subplot(gs1[1]) + +example_plot(ax1) +example_plot(ax2) + +gs1.tight_layout(fig, rect=[0, 0, 0.5, 1]) + +gs2 = gridspec.GridSpec(3, 1) + +for ss in gs2: + ax = fig.add_subplot(ss) + example_plot(ax) + ax.set_title("") + ax.set_xlabel("") + +ax.set_xlabel("x-label", fontsize=12) + +gs2.tight_layout(fig, rect=[0.5, 0, 1, 1], h_pad=0.5) + +top = min(gs1.top, gs2.top) +bottom = max(gs1.bottom, gs2.bottom) + +gs1.update(top=top, bottom=bottom) +gs2.update(top=top, bottom=bottom) + +top = min(gs1.top, gs2.top) +bottom = max(gs1.bottom, gs2.bottom) + +gs1.tight_layout(fig, rect=[None, 0 + (bottom-gs1.bottom), + 0.5, 1 - (gs1.top-top)]) +gs2.tight_layout(fig, rect=[0.5, 0 + (bottom-gs2.bottom), + None, 1 - (gs2.top-top)], + h_pad=0.5) + +############################################################################### +# Use with AxesGrid1 +# ------------------ +# +# While limited, the axes_grid1 toolkit is also supported. + +from mpl_toolkits.axes_grid1 import Grid + +plt.close('all') +fig = plt.figure() +grid = Grid(fig, rect=111, nrows_ncols=(2, 2), + axes_pad=0.25, label_mode='L', + ) + +for ax in grid: + example_plot(ax) +ax.title.set_visible(False) + +plt.tight_layout() + +############################################################################### +# Colorbar +# -------- +# +# If you create a colorbar with the :func:`~matplotlib.pyplot.colorbar` +# command, the created colorbar is an instance of Axes, *not* Subplot, so +# tight_layout does not work. With Matplotlib v1.1, you may create a +# colorbar as a subplot using the gridspec. + +plt.close('all') +arr = np.arange(100).reshape((10, 10)) +fig = plt.figure(figsize=(4, 4)) +im = plt.imshow(arr, interpolation="none") + +plt.colorbar(im, use_gridspec=True) + +plt.tight_layout() + +############################################################################### +# Another option is to use AxesGrid1 toolkit to +# explicitly create an axes for colorbar. + +from mpl_toolkits.axes_grid1 import make_axes_locatable + +plt.close('all') +arr = np.arange(100).reshape((10, 10)) +fig = plt.figure(figsize=(4, 4)) +im = plt.imshow(arr, interpolation="none") + +divider = make_axes_locatable(plt.gca()) +cax = divider.append_axes("right", "5%", pad="3%") +plt.colorbar(im, cax=cax) + +plt.tight_layout() diff --git a/tutorials/03_advanced/README.txt b/tutorials/03_advanced/README.txt new file mode 100644 index 000000000000..0cec354a503f --- /dev/null +++ b/tutorials/03_advanced/README.txt @@ -0,0 +1,7 @@ +.. _tutorials-advanced: + +Advanced +======== + +These tutorials cover advanced topics for experienced Matplotlib +users and developers. diff --git a/tutorials/03_advanced/path_tutorial.py b/tutorials/03_advanced/path_tutorial.py new file mode 100644 index 000000000000..2aa88f3f9410 --- /dev/null +++ b/tutorials/03_advanced/path_tutorial.py @@ -0,0 +1,222 @@ +""" +============= +Path Tutorial +============= + +Defining paths in your Matplotlib visualization. + +The object underlying all of the :mod:`matplotlib.patch` objects is +the :class:`~matplotlib.path.Path`, which supports the standard set of +moveto, lineto, curveto commands to draw simple and compound outlines +consisting of line segments and splines. The ``Path`` is instantiated +with a (N,2) array of (x,y) vertices, and a N-length array of path +codes. For example to draw the unit rectangle from (0,0) to (1,1), we +could use this code +""" + +import matplotlib.pyplot as plt +from matplotlib.path import Path +import matplotlib.patches as patches + +verts = [ + (0., 0.), # left, bottom + (0., 1.), # left, top + (1., 1.), # right, top + (1., 0.), # right, bottom + (0., 0.), # ignored + ] + +codes = [Path.MOVETO, + Path.LINETO, + Path.LINETO, + Path.LINETO, + Path.CLOSEPOLY, + ] + +path = Path(verts, codes) + +fig = plt.figure() +ax = fig.add_subplot(111) +patch = patches.PathPatch(path, facecolor='orange', lw=2) +ax.add_patch(patch) +ax.set_xlim(-2, 2) +ax.set_ylim(-2, 2) +plt.show() + + +############################################################################### +# The following path codes are recognized +# +# ============== ================================= ==================================================================================================================== +# Code Vertices Description +# ============== ================================= ==================================================================================================================== +# ``STOP`` 1 (ignored) A marker for the end of the entire path (currently not required and ignored) +# ``MOVETO`` 1 Pick up the pen and move to the given vertex. +# ``LINETO`` 1 Draw a line from the current position to the given vertex. +# ``CURVE3`` 2 (1 control point, 1 endpoint) Draw a quadratic Bézier curve from the current position, with the given control point, to the given end point. +# ``CURVE4`` 3 (2 control points, 1 endpoint) Draw a cubic Bézier curve from the current position, with the given control points, to the given end point. +# ``CLOSEPOLY`` 1 (point itself is ignored) Draw a line segment to the start point of the current polyline. +# ============== ================================= ==================================================================================================================== +# +# +# .. path-curves: +# +# +# Bézier example +# ============== +# +# Some of the path components require multiple vertices to specify them: +# for example CURVE 3 is a `bézier +# `_ curve with one +# control point and one end point, and CURVE4 has three vertices for the +# two control points and the end point. The example below shows a +# CURVE4 Bézier spline -- the bézier curve will be contained in the +# convex hull of the start point, the two control points, and the end +# point + +verts = [ + (0., 0.), # P0 + (0.2, 1.), # P1 + (1., 0.8), # P2 + (0.8, 0.), # P3 + ] + +codes = [Path.MOVETO, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, + ] + +path = Path(verts, codes) + +fig = plt.figure() +ax = fig.add_subplot(111) +patch = patches.PathPatch(path, facecolor='none', lw=2) +ax.add_patch(patch) + +xs, ys = zip(*verts) +ax.plot(xs, ys, 'x--', lw=2, color='black', ms=10) + +ax.text(-0.05, -0.05, 'P0') +ax.text(0.15, 1.05, 'P1') +ax.text(1.05, 0.85, 'P2') +ax.text(0.85, -0.05, 'P3') + +ax.set_xlim(-0.1, 1.1) +ax.set_ylim(-0.1, 1.1) +plt.show() + +############################################################################### +# .. compound_paths: +# +# Compound paths +# ============== +# +# All of the simple patch primitives in matplotlib, Rectangle, Circle, +# Polygon, etc, are implemented with simple path. Plotting functions +# like :meth:`~matplotlib.axes.Axes.hist` and +# :meth:`~matplotlib.axes.Axes.bar`, which create a number of +# primitives, e.g., a bunch of Rectangles, can usually be implemented more +# efficiently using a compound path. The reason ``bar`` creates a list +# of rectangles and not a compound path is largely historical: the +# :class:`~matplotlib.path.Path` code is comparatively new and ``bar`` +# predates it. While we could change it now, it would break old code, +# so here we will cover how to create compound paths, replacing the +# functionality in bar, in case you need to do so in your own code for +# efficiency reasons, e.g., you are creating an animated bar plot. +# +# We will make the histogram chart by creating a series of rectangles +# for each histogram bar: the rectangle width is the bin width and the +# rectangle height is the number of datapoints in that bin. First we'll +# create some random normally distributed data and compute the +# histogram. Because numpy returns the bin edges and not centers, the +# length of ``bins`` is 1 greater than the length of ``n`` in the +# example below:: +# +# # histogram our data with numpy +# data = np.random.randn(1000) +# n, bins = np.histogram(data, 100) +# +# We'll now extract the corners of the rectangles. Each of the +# ``left``, ``bottom``, etc, arrays below is ``len(n)``, where ``n`` is +# the array of counts for each histogram bar:: +# +# # get the corners of the rectangles for the histogram +# left = np.array(bins[:-1]) +# right = np.array(bins[1:]) +# bottom = np.zeros(len(left)) +# top = bottom + n +# +# Now we have to construct our compound path, which will consist of a +# series of ``MOVETO``, ``LINETO`` and ``CLOSEPOLY`` for each rectangle. +# For each rectangle, we need 5 vertices: 1 for the ``MOVETO``, 3 for +# the ``LINETO``, and 1 for the ``CLOSEPOLY``. As indicated in the +# table above, the vertex for the closepoly is ignored but we still need +# it to keep the codes aligned with the vertices:: +# +# nverts = nrects*(1+3+1) +# verts = np.zeros((nverts, 2)) +# codes = np.ones(nverts, int) * path.Path.LINETO +# codes[0::5] = path.Path.MOVETO +# codes[4::5] = path.Path.CLOSEPOLY +# verts[0::5,0] = left +# verts[0::5,1] = bottom +# verts[1::5,0] = left +# verts[1::5,1] = top +# verts[2::5,0] = right +# verts[2::5,1] = top +# verts[3::5,0] = right +# verts[3::5,1] = bottom +# +# All that remains is to create the path, attach it to a +# :class:`~matplotlib.patch.PathPatch`, and add it to our axes:: +# +# barpath = path.Path(verts, codes) +# patch = patches.PathPatch(barpath, facecolor='green', +# edgecolor='yellow', alpha=0.5) +# ax.add_patch(patch) + +import numpy as np +import matplotlib.patches as patches +import matplotlib.path as path + +fig = plt.figure() +ax = fig.add_subplot(111) + +# Fixing random state for reproducibility +np.random.seed(19680801) + +# histogram our data with numpy +data = np.random.randn(1000) +n, bins = np.histogram(data, 100) + +# get the corners of the rectangles for the histogram +left = np.array(bins[:-1]) +right = np.array(bins[1:]) +bottom = np.zeros(len(left)) +top = bottom + n +nrects = len(left) + +nverts = nrects*(1+3+1) +verts = np.zeros((nverts, 2)) +codes = np.ones(nverts, int) * path.Path.LINETO +codes[0::5] = path.Path.MOVETO +codes[4::5] = path.Path.CLOSEPOLY +verts[0::5, 0] = left +verts[0::5, 1] = bottom +verts[1::5, 0] = left +verts[1::5, 1] = top +verts[2::5, 0] = right +verts[2::5, 1] = top +verts[3::5, 0] = right +verts[3::5, 1] = bottom + +barpath = path.Path(verts, codes) +patch = patches.PathPatch(barpath, facecolor='green', + edgecolor='yellow', alpha=0.5) +ax.add_patch(patch) + +ax.set_xlim(left[0], right[-1]) +ax.set_ylim(bottom.min(), top.max()) + +plt.show() diff --git a/tutorials/03_advanced/patheffects_guide.py b/tutorials/03_advanced/patheffects_guide.py new file mode 100644 index 000000000000..4f2c89cf3315 --- /dev/null +++ b/tutorials/03_advanced/patheffects_guide.py @@ -0,0 +1,119 @@ +""" +================== +Path effects guide +================== + +Defining paths that objects follow on a canvas. + +.. py:module:: matplotlib.patheffects + + +Matplotlib's :mod:`~matplotlib.patheffects` module provides functionality to +apply a multiple draw stage to any Artist which can be rendered via a +:class:`~matplotlib.path.Path`. + +Artists which can have a path effect applied to them include :class:`~matplotlib.patches.Patch`, +:class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.collections.Collection` and even +:class:`~matplotlib.text.Text`. Each artist's path effects can be controlled via the +``set_path_effects`` method (:class:`~matplotlib.artist.Artist.set_path_effects`), which takes +an iterable of :class:`AbstractPathEffect` instances. + +The simplest path effect is the :class:`Normal` effect, which simply +draws the artist without any effect: +""" + +import matplotlib.pyplot as plt +import matplotlib.patheffects as path_effects + +fig = plt.figure(figsize=(5, 1.5)) +text = fig.text(0.5, 0.5, 'Hello path effects world!\nThis is the normal ' + 'path effect.\nPretty dull, huh?', + ha='center', va='center', size=20) +text.set_path_effects([path_effects.Normal()]) +plt.show() + +############################################################################### +# Whilst the plot doesn't look any different to what you would expect without any path +# effects, the drawing of the text now been changed to use the path effects +# framework, opening up the possibilities for more interesting examples. +# +# Adding a shadow +# --------------- +# +# A far more interesting path effect than :class:`Normal` is the +# drop-shadow, which we can apply to any of our path based artists. The classes +# :class:`SimplePatchShadow` and +# :class:`SimpleLineShadow` do precisely this by drawing either a filled +# patch or a line patch below the original artist: + +import matplotlib.patheffects as path_effects + +text = plt.text(0.5, 0.5, 'Hello path effects world!', + path_effects=[path_effects.withSimplePatchShadow()]) + +plt.plot([0, 3, 2, 5], linewidth=5, color='blue', + path_effects=[path_effects.SimpleLineShadow(), + path_effects.Normal()]) +plt.show() + +############################################################################### +# Notice the two approaches to setting the path effects in this example. The +# first uses the ``with*`` classes to include the desired functionality automatically +# followed with the "normal" effect, whereas the latter explicitly defines the two path +# effects to draw. +# +# Making an artist stand out +# -------------------------- +# +# One nice way of making artists visually stand out is to draw an outline in a bold +# color below the actual artist. The :class:`Stroke` path effect +# makes this a relatively simple task: + +fig = plt.figure(figsize=(7, 1)) +text = fig.text(0.5, 0.5, 'This text stands out because of\n' + 'its black border.', color='white', + ha='center', va='center', size=30) +text.set_path_effects([path_effects.Stroke(linewidth=3, foreground='black'), + path_effects.Normal()]) +plt.show() + +############################################################################### +# It is important to note that this effect only works because we have drawn the text +# path twice; once with a thick black line, and then once with the original text +# path on top. +# +# You may have noticed that the keywords to :class:`Stroke` and +# :class:`SimplePatchShadow` and :class:`SimpleLineShadow` are not the usual Artist +# keywords (such as ``facecolor`` and ``edgecolor`` etc.). This is because with these +# path effects we are operating at lower level of matplotlib. In fact, the keywords +# which are accepted are those for a :class:`matplotlib.backend_bases.GraphicsContextBase` +# instance, which have been designed for making it easy to create new backends - and not +# for its user interface. +# +# +# Greater control of the path effect artist +# ----------------------------------------- +# +# As already mentioned, some of the path effects operate at a lower level than most users +# will be used to, meaning that setting keywords such as ``facecolor`` and ``edgecolor`` +# raise an AttributeError. Luckily there is a generic :class:`PathPatchEffect` path effect +# which creates a :class:`~matplotlib.patches.PathPatch` class with the original path. +# The keywords to this effect are identical to those of :class:`~matplotlib.patches.PathPatch`: + +fig = plt.figure(figsize=(8, 1)) +t = fig.text(0.02, 0.5, 'Hatch shadow', fontsize=75, weight=1000, va='center') +t.set_path_effects([path_effects.PathPatchEffect(offset=(4, -4), hatch='xxxx', + facecolor='gray'), + path_effects.PathPatchEffect(edgecolor='white', linewidth=1.1, + facecolor='black')]) +plt.show() + +############################################################################### +# .. +# Headings for future consideration: +# +# Implementing a custom path effect +# --------------------------------- +# +# What is going on under the hood +# -------------------------------- diff --git a/tutorials/03_advanced/transforms_tutorial.py b/tutorials/03_advanced/transforms_tutorial.py new file mode 100644 index 000000000000..62eb76a2a1ce --- /dev/null +++ b/tutorials/03_advanced/transforms_tutorial.py @@ -0,0 +1,461 @@ +""" +======================== +Transformations Tutorial +======================== + +Transforming visuals in Matplotlib. + +Like any graphics packages, matplotlib is built on top of a +transformation framework to easily move between coordinate systems, +the userland `data` coordinate system, the `axes` coordinate system, +the `figure` coordinate system, and the `display` coordinate system. +In 95% of your plotting, you won't need to think about this, as it +happens under the hood, but as you push the limits of custom figure +generation, it helps to have an understanding of these objects so you +can reuse the existing transformations matplotlib makes available to +you, or create your own (see :mod:`matplotlib.transforms`). The table +below summarizes the existing coordinate systems, the transformation +object you should use to work in that coordinate system, and the +description of that system. In the `Transformation Object` column, +``ax`` is a :class:`~matplotlib.axes.Axes` instance, and ``fig`` is a +:class:`~matplotlib.figure.Figure` instance. + +========== ===================== ==================================================================================== +Coordinate Transformation Object Description +========== ===================== ==================================================================================== +`data` ``ax.transData`` The userland data coordinate system, controlled by the xlim and ylim +`axes` ``ax.transAxes`` The coordinate system of the :class:`~matplotlib.axes.Axes`; (0,0) is + bottom left of the axes, and (1,1) is top right of the axes. +`figure` ``fig.transFigure`` The coordinate system of the :class:`~matplotlib.figure.Figure`; (0,0) + is bottom left of the figure, and (1,1) is top right of the figure. +`display` `None` This is the pixel coordinate system of the display; (0,0) is the bottom + left of the display, and (width, height) is the top right of the display in pixels. + Alternatively, the identity transform + (:class:`matplotlib.transforms.IdentityTransform()`) may be used instead of None. +========== ===================== ==================================================================================== + + +All of the transformation objects in the table above take inputs in +their coordinate system, and transform the input to the `display` +coordinate system. That is why the `display` coordinate system has +`None` for the `Transformation Object` column -- it already is in +display coordinates. The transformations also know how to invert +themselves, to go from `display` back to the native coordinate system. +This is particularly useful when processing events from the user +interface, which typically occur in display space, and you want to +know where the mouse click or key-press occurred in your data +coordinate system. + +.. _data-coords: + +Data coordinates +================ + +Let's start with the most commonly used coordinate, the `data` +coordinate system. Whenever you add data to the axes, matplotlib +updates the datalimits, most commonly updated with the +:meth:`~matplotlib.axes.Axes.set_xlim` and +:meth:`~matplotlib.axes.Axes.set_ylim` methods. For example, in the +figure below, the data limits stretch from 0 to 10 on the x-axis, and +-1 to 1 on the y-axis. +""" + +import numpy as np +import matplotlib.pyplot as plt + +x = np.arange(0, 10, 0.005) +y = np.exp(-x/2.) * np.sin(2*np.pi*x) + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.plot(x, y) +ax.set_xlim(0, 10) +ax.set_ylim(-1, 1) + +plt.show() + +############################################################################### +# You can use the ``ax.transData`` instance to transform from your +# `data` to your `display` coordinate system, either a single point or a +# sequence of points as shown below: +# +# .. sourcecode:: ipython +# +# In [14]: type(ax.transData) +# Out[14]: +# +# In [15]: ax.transData.transform((5, 0)) +# Out[15]: array([ 335.175, 247. ]) +# +# In [16]: ax.transData.transform([(5, 0), (1,2)]) +# Out[16]: +# array([[ 335.175, 247. ], +# [ 132.435, 642.2 ]]) +# +# You can use the :meth:`~matplotlib.transforms.Transform.inverted` +# method to create a transform which will take you from display to data +# coordinates: +# +# .. sourcecode:: ipython +# +# In [41]: inv = ax.transData.inverted() +# +# In [42]: type(inv) +# Out[42]: +# +# In [43]: inv.transform((335.175, 247.)) +# Out[43]: array([ 5., 0.]) +# +# If your are typing along with this tutorial, the exact values of the +# display coordinates may differ if you have a different window size or +# dpi setting. Likewise, in the figure below, the display labeled +# points are probably not the same as in the ipython session because the +# documentation figure size defaults are different. + +x = np.arange(0, 10, 0.005) +y = np.exp(-x/2.) * np.sin(2*np.pi*x) + +fig = plt.figure() +ax = fig.add_subplot(111) +ax.plot(x, y) +ax.set_xlim(0, 10) +ax.set_ylim(-1, 1) + +xdata, ydata = 5, 0 +xdisplay, ydisplay = ax.transData.transform_point((xdata, ydata)) + +bbox = dict(boxstyle="round", fc="0.8") +arrowprops = dict( + arrowstyle="->", + connectionstyle="angle,angleA=0,angleB=90,rad=10") + +offset = 72 +ax.annotate('data = (%.1f, %.1f)' % (xdata, ydata), + (xdata, ydata), xytext=(-2*offset, offset), textcoords='offset points', + bbox=bbox, arrowprops=arrowprops) + + +disp = ax.annotate('display = (%.1f, %.1f)' % (xdisplay, ydisplay), + (xdisplay, ydisplay), xytext=(0.5*offset, -offset), + xycoords='figure pixels', + textcoords='offset points', + bbox=bbox, arrowprops=arrowprops) + + +plt.show() + +############################################################################### +# .. note:: +# +# If you run the source code in the example above in a GUI backend, +# you may also find that the two arrows for the `data` and `display` +# annotations do not point to exactly the same point. This is because +# the display point was computed before the figure was displayed, and +# the GUI backend may slightly resize the figure when it is created. +# The effect is more pronounced if you resize the figure yourself. +# This is one good reason why you rarely want to work in display +# space, but you can connect to the ``'on_draw'`` +# :class:`~matplotlib.backend_bases.Event` to update figure +# coordinates on figure draws; see :ref:`event-handling-tutorial`. +# +# When you change the x or y limits of your axes, the data limits are +# updated so the transformation yields a new display point. Note that +# when we just change the ylim, only the y-display coordinate is +# altered, and when we change the xlim too, both are altered. More on +# this later when we talk about the +# :class:`~matplotlib.transforms.Bbox`. +# +# .. sourcecode:: ipython +# +# In [54]: ax.transData.transform((5, 0)) +# Out[54]: array([ 335.175, 247. ]) +# +# In [55]: ax.set_ylim(-1,2) +# Out[55]: (-1, 2) +# +# In [56]: ax.transData.transform((5, 0)) +# Out[56]: array([ 335.175 , 181.13333333]) +# +# In [57]: ax.set_xlim(10,20) +# Out[57]: (10, 20) +# +# In [58]: ax.transData.transform((5, 0)) +# Out[58]: array([-171.675 , 181.13333333]) +# +# +# .. _axes-coords: +# +# Axes coordinates +# ================ +# +# After the `data` coordinate system, `axes` is probably the second most +# useful coordinate system. Here the point (0,0) is the bottom left of +# your axes or subplot, (0.5, 0.5) is the center, and (1.0, 1.0) is the +# top right. You can also refer to points outside the range, so (-0.1, +# 1.1) is to the left and above your axes. This coordinate system is +# extremely useful when placing text in your axes, because you often +# want a text bubble in a fixed, location, e.g., the upper left of the axes +# pane, and have that location remain fixed when you pan or zoom. Here +# is a simple example that creates four panels and labels them 'A', 'B', +# 'C', 'D' as you often see in journals. + +fig = plt.figure() +for i, label in enumerate(('A', 'B', 'C', 'D')): + ax = fig.add_subplot(2, 2, i+1) + ax.text(0.05, 0.95, label, transform=ax.transAxes, + fontsize=16, fontweight='bold', va='top') + +plt.show() + +############################################################################### +# You can also make lines or patches in the axes coordinate system, but +# this is less useful in my experience than using ``ax.transAxes`` for +# placing text. Nonetheless, here is a silly example which plots some +# random dots in `data` space, and overlays a semi-transparent +# :class:`~matplotlib.patches.Circle` centered in the middle of the axes +# with a radius one quarter of the axes -- if your axes does not +# preserve aspect ratio (see :meth:`~matplotlib.axes.Axes.set_aspect`), +# this will look like an ellipse. Use the pan/zoom tool to move around, +# or manually change the data xlim and ylim, and you will see the data +# move, but the circle will remain fixed because it is not in `data` +# coordinates and will always remain at the center of the axes. + +import matplotlib.patches as patches + +fig = plt.figure() +ax = fig.add_subplot(111) +x, y = 10*np.random.rand(2, 1000) +ax.plot(x, y, 'go') # plot some data in data coordinates + +circ = patches.Circle((0.5, 0.5), 0.25, transform=ax.transAxes, + facecolor='yellow', alpha=0.5) +ax.add_patch(circ) +plt.show() + +############################################################################### +# .. blended_transformations: +# +# Blended transformations +# ======================= +# +# Drawing in `blended` coordinate spaces which mix `axes` with `data` +# coordinates is extremely useful, for example to create a horizontal +# span which highlights some region of the y-data but spans across the +# x-axis regardless of the data limits, pan or zoom level, etc. In fact +# these blended lines and spans are so useful, we have built in +# functions to make them easy to plot (see +# :meth:`~matplotlib.axes.Axes.axhline`, +# :meth:`~matplotlib.axes.Axes.axvline`, +# :meth:`~matplotlib.axes.Axes.axhspan`, +# :meth:`~matplotlib.axes.Axes.axvspan`) but for didactic purposes we +# will implement the horizontal span here using a blended +# transformation. This trick only works for separable transformations, +# like you see in normal Cartesian coordinate systems, but not on +# inseparable transformations like the +# :class:`~matplotlib.projections.polar.PolarAxes.PolarTransform`. + +import matplotlib.transforms as transforms + +fig = plt.figure() +ax = fig.add_subplot(111) + +x = np.random.randn(1000) + +ax.hist(x, 30) +ax.set_title(r'$\sigma=1 \/ \dots \/ \sigma=2$', fontsize=16) + +# the x coords of this transformation are data, and the +# y coord are axes +trans = transforms.blended_transform_factory( + ax.transData, ax.transAxes) + +# highlight the 1..2 stddev region with a span. +# We want x to be in data coordinates and y to +# span from 0..1 in axes coords +rect = patches.Rectangle((1,0), width=1, height=1, + transform=trans, color='yellow', + alpha=0.5) + +ax.add_patch(rect) + +plt.show() + +############################################################################### +# .. note:: +# +# The blended transformations where x is in data coords and y in axes +# coordinates is so useful that we have helper methods to return the +# versions mpl uses internally for drawing ticks, ticklabels, etc. +# The methods are :meth:`matplotlib.axes.Axes.get_xaxis_transform` and +# :meth:`matplotlib.axes.Axes.get_yaxis_transform`. So in the example +# above, the call to +# :meth:`~matplotlib.transforms.blended_transform_factory` can be +# replaced by ``get_xaxis_transform``:: +# +# trans = ax.get_xaxis_transform() +# +# .. offset-transforms-shadow: +# +# Using offset transforms to create a shadow effect +# ================================================= +# +# One use of transformations is to create a new transformation that is +# offset from another transformation, e.g., to place one object shifted a +# bit relative to another object. Typically you want the shift to be in +# some physical dimension, like points or inches rather than in data +# coordinates, so that the shift effect is constant at different zoom +# levels and dpi settings. +# +# One use for an offset is to create a shadow effect, where you draw one +# object identical to the first just to the right of it, and just below +# it, adjusting the zorder to make sure the shadow is drawn first and +# then the object it is shadowing above it. The transforms module has a +# helper transformation +# :class:`~matplotlib.transforms.ScaledTranslation`. It is +# instantiated with:: +# +# trans = ScaledTranslation(xt, yt, scale_trans) +# +# where `xt` and `yt` are the translation offsets, and `scale_trans` is +# a transformation which scales `xt` and `yt` at transformation time +# before applying the offsets. A typical use case is to use the figure +# ``fig.dpi_scale_trans`` transformation for the `scale_trans` argument, +# to first scale `xt` and `yt` specified in points to `display` space +# before doing the final offset. The dpi and inches offset is a +# common-enough use case that we have a special helper function to +# create it in :func:`matplotlib.transforms.offset_copy`, which returns +# a new transform with an added offset. But in the example below, we'll +# create the offset transform ourselves. Note the use of the plus +# operator in:: +# +# offset = transforms.ScaledTranslation(dx, dy, +# fig.dpi_scale_trans) +# shadow_transform = ax.transData + offset +# +# showing that can chain transformations using the addition operator. +# This code says: first apply the data transformation ``ax.transData`` +# and then translate the data by `dx` and `dy` points. In typography, +# a`point `_ is +# 1/72 inches, and by specifying your offsets in points, your figure +# will look the same regardless of the dpi resolution it is saved in. + +fig = plt.figure() +ax = fig.add_subplot(111) + +# make a simple sine wave +x = np.arange(0., 2., 0.01) +y = np.sin(2*np.pi*x) +line, = ax.plot(x, y, lw=3, color='blue') + +# shift the object over 2 points, and down 2 points +dx, dy = 2/72., -2/72. +offset = transforms.ScaledTranslation(dx, dy, fig.dpi_scale_trans) +shadow_transform = ax.transData + offset + +# now plot the same data with our offset transform; +# use the zorder to make sure we are below the line +ax.plot(x, y, lw=3, color='gray', + transform=shadow_transform, + zorder=0.5*line.get_zorder()) + +ax.set_title('creating a shadow effect with an offset transform') +plt.show() + +############################################################################### +# .. transformation-pipeline: +# +# The transformation pipeline +# =========================== +# +# The ``ax.transData`` transform we have been working with in this +# tutorial is a composite of three different transformations that +# comprise the transformation pipeline from `data` -> `display` +# coordinates. Michael Droettboom implemented the transformations +# framework, taking care to provide a clean API that segregated the +# nonlinear projections and scales that happen in polar and logarithmic +# plots, from the linear affine transformations that happen when you pan +# and zoom. There is an efficiency here, because you can pan and zoom +# in your axes which affects the affine transformation, but you may not +# need to compute the potentially expensive nonlinear scales or +# projections on simple navigation events. It is also possible to +# multiply affine transformation matrices together, and then apply them +# to coordinates in one step. This is not true of all possible +# transformations. +# +# +# Here is how the ``ax.transData`` instance is defined in the basic +# separable axis :class:`~matplotlib.axes.Axes` class:: +# +# self.transData = self.transScale + (self.transLimits + self.transAxes) +# +# We've been introduced to the ``transAxes`` instance above in +# :ref:`axes-coords`, which maps the (0,0), (1,1) corners of the +# axes or subplot bounding box to `display` space, so let's look at +# these other two pieces. +# +# ``self.transLimits`` is the transformation that takes you from +# ``data`` to ``axes`` coordinates; i.e., it maps your view xlim and ylim +# to the unit space of the axes (and ``transAxes`` then takes that unit +# space to display space). We can see this in action here +# +# .. sourcecode:: ipython +# +# In [80]: ax = subplot(111) +# +# In [81]: ax.set_xlim(0, 10) +# Out[81]: (0, 10) +# +# In [82]: ax.set_ylim(-1,1) +# Out[82]: (-1, 1) +# +# In [84]: ax.transLimits.transform((0,-1)) +# Out[84]: array([ 0., 0.]) +# +# In [85]: ax.transLimits.transform((10,-1)) +# Out[85]: array([ 1., 0.]) +# +# In [86]: ax.transLimits.transform((10,1)) +# Out[86]: array([ 1., 1.]) +# +# In [87]: ax.transLimits.transform((5,0)) +# Out[87]: array([ 0.5, 0.5]) +# +# and we can use this same inverted transformation to go from the unit +# `axes` coordinates back to `data` coordinates. +# +# .. sourcecode:: ipython +# +# In [90]: inv.transform((0.25, 0.25)) +# Out[90]: array([ 2.5, -0.5]) +# +# The final piece is the ``self.transScale`` attribute, which is +# responsible for the optional non-linear scaling of the data, e.g., for +# logarithmic axes. When an Axes is initially setup, this is just set to +# the identity transform, since the basic matplotlib axes has linear +# scale, but when you call a logarithmic scaling function like +# :meth:`~matplotlib.axes.Axes.semilogx` or explicitly set the scale to +# logarithmic with :meth:`~matplotlib.axes.Axes.set_xscale`, then the +# ``ax.transScale`` attribute is set to handle the nonlinear projection. +# The scales transforms are properties of the respective ``xaxis`` and +# ``yaxis`` :class:`~matplotlib.axis.Axis` instances. For example, when +# you call ``ax.set_xscale('log')``, the xaxis updates its scale to a +# :class:`matplotlib.scale.LogScale` instance. +# +# For non-separable axes the PolarAxes, there is one more piece to +# consider, the projection transformation. The ``transData`` +# :class:`matplotlib.projections.polar.PolarAxes` is similar to that for +# the typical separable matplotlib Axes, with one additional piece +# ``transProjection``:: +# +# self.transData = self.transScale + self.transProjection + \ +# (self.transProjectionAffine + self.transAxes) +# +# ``transProjection`` handles the projection from the space, +# e.g., latitude and longitude for map data, or radius and theta for polar +# data, to a separable Cartesian coordinate system. There are several +# projection examples in the ``matplotlib.projections`` package, and the +# best way to learn more is to open the source for those packages and +# see how to make your own, since matplotlib supports extensible axes +# and projections. Michael Droettboom has provided a nice tutorial +# example of creating a hammer projection axes; see +# :ref:`sphx_glr_gallery_api_custom_projection_example.py`. diff --git a/tutorials/README.txt b/tutorials/README.txt new file mode 100644 index 000000000000..74d339265bdb --- /dev/null +++ b/tutorials/README.txt @@ -0,0 +1,12 @@ +.. _tutorials: + +Tutorials +========= + +This page contains more in-depth guides for using Matplotlib. +It is broken up into beginner, intermediate, and advanced sections, +as well as sections covering specific topics. + +For shorter examples, see our `examples page <../gallery/index.html>`_. +You can also find `external resources <../resources/index.html>`_ and +a `FAQ <../faq/index.html>`_ in our `user guide <../contents.html>`_. diff --git a/tutorials/colors/README.txt b/tutorials/colors/README.txt new file mode 100644 index 000000000000..1699c979264e --- /dev/null +++ b/tutorials/colors/README.txt @@ -0,0 +1,11 @@ +.. _tutorials-colors: + +Colors +====== + +Matplotlib has support for visualizing information with a wide array +of colors and colormaps. These tutorials cover the basics of how +these colormaps look, how you can create your own, and how you can +customize colormaps for your use case. + +For even more information see the :ref:`examples page `. diff --git a/tutorials/colors/colormapnorms.py b/tutorials/colors/colormapnorms.py new file mode 100644 index 000000000000..eb344f0164fe --- /dev/null +++ b/tutorials/colors/colormapnorms.py @@ -0,0 +1,235 @@ +""" +Colormap Normalization +====================== + +Objects that use colormaps by default linearly map the colors in the +colormap from data values *vmin* to *vmax*. For example:: + + pcm = ax.pcolormesh(x, y, Z, vmin=-1., vmax=1., cmap='RdBu_r') + +will map the data in *Z* linearly from -1 to +1, so *Z=0* will +give a color at the center of the colormap *RdBu_r* (white in this +case). + +Matplotlib does this mapping in two steps, with a normalization from +[0,1] occurring first, and then mapping onto the indices in the +colormap. Normalizations are classes defined in the +:func:`matplotlib.colors` module. The default, linear normalization is +:func:`matplotlib.colors.Normalize`. + +Artists that map data to color pass the arguments *vmin* and *vmax* to +construct a :func:`matplotlib.colors.Normalize` instance, then call it: + +.. ipython:: + + In [1]: import matplotlib as mpl + + In [2]: norm = mpl.colors.Normalize(vmin=-1.,vmax=1.) + + In [3]: norm(0.) + Out[3]: 0.5 + +However, there are sometimes cases where it is useful to map data to +colormaps in a non-linear fashion. + +Logarithmic +----------- + +One of the most common transformations is to plot data by taking +its logarithm (to the base-10). This transformation is useful to +display changes across disparate scales. Using :func:`colors.LogNorm` +normalizes the data via :math:`log_{10}`. In the example below, +there are two bumps, one much smaller than the other. Using +:func:`colors.LogNorm`, the shape and location of each bump can clearly +be seen: +""" +import numpy as np +import matplotlib.pyplot as plt +import matplotlib.colors as colors +from matplotlib.mlab import bivariate_normal + +N = 100 +X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)] + +# A low hump with a spike coming out of the top right. Needs to have +# z/colour axis on a log scale so we see both hump and spike. linear +# scale only shows the spike. +Z1 = bivariate_normal(X, Y, 0.1, 0.2, 1.0, 1.0) + \ + 0.1 * bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) + +fig, ax = plt.subplots(2, 1) + +pcm = ax[0].pcolor(X, Y, Z1, + norm=colors.LogNorm(vmin=Z1.min(), vmax=Z1.max()), + cmap='PuBu_r') +fig.colorbar(pcm, ax=ax[0], extend='max') + +pcm = ax[1].pcolor(X, Y, Z1, cmap='PuBu_r') +fig.colorbar(pcm, ax=ax[1], extend='max') +fig.show() + +############################################################################### +# Symmetric logarithmic +# --------------------- +# +# Similarly, it sometimes happens that there is data that is positive +# and negative, but we would still like a logarithmic scaling applied to +# both. In this case, the negative numbers are also scaled +# logarithmically, and mapped to smaller numbers; e.g., if `vmin=-vmax`, +# then they the negative numbers are mapped from 0 to 0.5 and the +# positive from 0.5 to 1. +# +# Since the logarithm of values close to zero tends toward infinity, a +# small range around zero needs to be mapped linearly. The parameter +# *linthresh* allows the user to specify the size of this range +# (-*linthresh*, *linthresh*). The size of this range in the colormap is +# set by *linscale*. When *linscale* == 1.0 (the default), the space used +# for the positive and negative halves of the linear range will be equal +# to one decade in the logarithmic range. + +N = 100 +X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)] +Z1 = (bivariate_normal(X, Y, 1., 1., 1.0, 1.0))**2 \ + - 0.4 * (bivariate_normal(X, Y, 1.0, 1.0, -1.0, 0.0))**2 +Z1 = Z1/0.03 + +fig, ax = plt.subplots(2, 1) + +pcm = ax[0].pcolormesh(X, Y, Z1, + norm=colors.SymLogNorm(linthresh=0.03, linscale=0.03, + vmin=-1.0, vmax=1.0), + cmap='RdBu_r') +fig.colorbar(pcm, ax=ax[0], extend='both') + +pcm = ax[1].pcolormesh(X, Y, Z1, cmap='RdBu_r', vmin=-np.max(Z1)) +fig.colorbar(pcm, ax=ax[1], extend='both') +fig.show() + +############################################################################### +# Power-law +# --------- +# +# Sometimes it is useful to remap the colors onto a power-law +# relationship (i.e. :math:`y=x^{\gamma}`, where :math:`\gamma` is the +# power). For this we use the :func:`colors.PowerNorm`. It takes as an +# argument *gamma* (*gamma* == 1.0 will just yield the default linear +# normalization): +# +# .. note:: +# +# There should probably be a good reason for plotting the data using +# this type of transformation. Technical viewers are used to linear +# and logarithmic axes and data transformations. Power laws are less +# common, and viewers should explicitly be made aware that they have +# been used. + +N = 100 +X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)] +Z1 = (1 + np.sin(Y * 10.)) * X**(2.) + +fig, ax = plt.subplots(2, 1) + +pcm = ax[0].pcolormesh(X, Y, Z1, norm=colors.PowerNorm(gamma=1./2.), + cmap='PuBu_r') +fig.colorbar(pcm, ax=ax[0], extend='max') + +pcm = ax[1].pcolormesh(X, Y, Z1, cmap='PuBu_r') +fig.colorbar(pcm, ax=ax[1], extend='max') +fig.show() + +############################################################################### +# Discrete bounds +# --------------- +# +# Another normaization that comes with matplolib is +# :func:`colors.BoundaryNorm`. In addition to *vmin* and *vmax*, this +# takes as arguments boundaries between which data is to be mapped. The +# colors are then linearly distributed between these "bounds". For +# instance: +# +# .. ipython:: +# +# In [2]: import matplotlib.colors as colors +# +# In [3]: bounds = np.array([-0.25, -0.125, 0, 0.5, 1]) +# +# In [4]: norm = colors.BoundaryNorm(boundaries=bounds, ncolors=4) +# +# In [5]: print(norm([-0.2,-0.15,-0.02, 0.3, 0.8, 0.99])) +# [0 0 1 2 3 3] +# +# Note unlike the other norms, this norm returns values from 0 to *ncolors*-1. + +N = 100 +X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)] +Z1 = (bivariate_normal(X, Y, 1., 1., 1.0, 1.0))**2 \ + - 0.4 * (bivariate_normal(X, Y, 1.0, 1.0, -1.0, 0.0))**2 +Z1 = Z1/0.03 + +fig, ax = plt.subplots(3, 1, figsize=(8, 8)) +ax = ax.flatten() +# even bounds gives a contour-like effect +bounds = np.linspace(-1, 1, 10) +norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256) +pcm = ax[0].pcolormesh(X, Y, Z1, + norm=norm, + cmap='RdBu_r') +fig.colorbar(pcm, ax=ax[0], extend='both', orientation='vertical') + +# uneven bounds changes the colormapping: +bounds = np.array([-0.25, -0.125, 0, 0.5, 1]) +norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256) +pcm = ax[1].pcolormesh(X, Y, Z1, norm=norm, cmap='RdBu_r') +fig.colorbar(pcm, ax=ax[1], extend='both', orientation='vertical') + +pcm = ax[2].pcolormesh(X, Y, Z1, cmap='RdBu_r', vmin=-np.max(Z1)) +fig.colorbar(pcm, ax=ax[2], extend='both', orientation='vertical') +fig.show() + + +############################################################################### +# Custom normalization: Two linear ranges +# --------------------------------------- +# +# It is possible to define your own normalization. In the following +# example, we modify :func:`colors:SymLogNorm` to use different linear +# maps for the negative data values and the positive. (Note that this +# example is simple, and does not validate inputs or account for complex +# cases such as masked data) +# +# .. note:: +# This may appear soon as :func:`colors.OffsetNorm`. +# +# As above, non-symmetric mapping of data to color is non-standard +# practice for quantitative data, and should only be used advisedly. A +# practical example is having an ocean/land colormap where the land and +# ocean data span different ranges. + +N = 100 +X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)] +Z1 = (bivariate_normal(X, Y, 1., 1., 1.0, 1.0))**2 \ + - 0.4 * (bivariate_normal(X, Y, 1.0, 1.0, -1.0, 0.0))**2 +Z1 = Z1/0.03 + + +class MidpointNormalize(colors.Normalize): + def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False): + self.midpoint = midpoint + colors.Normalize.__init__(self, vmin, vmax, clip) + + def __call__(self, value, clip=None): + # I'm ignoring masked values and all kinds of edge cases to make a + # simple example... + x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1] + return np.ma.masked_array(np.interp(value, x, y)) + +fig, ax = plt.subplots(2, 1) + +pcm = ax[0].pcolormesh(X, Y, Z1, + norm=MidpointNormalize(midpoint=0.), + cmap='RdBu_r') +fig.colorbar(pcm, ax=ax[0], extend='both') + +pcm = ax[1].pcolormesh(X, Y, Z1, cmap='RdBu_r', vmin=-np.max(Z1)) +fig.colorbar(pcm, ax=ax[1], extend='both') +fig.show() diff --git a/tutorials/colors/colormaps.py b/tutorials/colors/colormaps.py new file mode 100644 index 000000000000..92c6e058b421 --- /dev/null +++ b/tutorials/colors/colormaps.py @@ -0,0 +1,396 @@ +""" +*********************** +Colormaps in Matplotlib +*********************** + +How (and why) to choose a particular colormap. + +Overview +======== + +The idea behind choosing a good colormap is to find a good representation in 3D +colorspace for your data set. The best colormap for any given data set depends +on many things including: + +- Whether representing form or metric data ([Ware]_) + +- Your knowledge of the data set (*e.g.*, is there a critical value + from which the other values deviate?) + +- If there is an intuitive color scheme for the parameter you are plotting + +- If there is a standard in the field the audience may be expecting + +For many applications, a perceptually uniform colormap is the best +choice --- one in which equal steps in data are perceived as equal +steps in the color space. Researchers have found that the human brain +perceives changes in the lightness parameter as changes in the data +much better than, for example, changes in hue. Therefore, colormaps +which have monotonically increasing lightness through the colormap +will be better interpreted by the viewer. A wonderful example of +perceptually uniform colormaps is [colorcet]_. + +Color can be represented in 3D space in various ways. One way to represent color +is using CIELAB. In CIELAB, color space is represented by lightness, +:math:`L^*`; red-green, :math:`a^*`; and yellow-blue, :math:`b^*`. The lightness +parameter :math:`L^*` can then be used to learn more about how the matplotlib +colormaps will be perceived by viewers. + +An excellent starting resource for learning about human perception of colormaps +is from [IBM]_. + + +Classes of colormaps +==================== + +Colormaps are often split into several categories based on their function (see, +*e.g.*, [Moreland]_): + +1. Sequential: change in lightness and often saturation of color + incrementally, often using a single hue; should be used for + representing information that has ordering. + +2. Diverging: change in lightness and possibly saturation of two + different colors that meet in the middle at an unsaturated color; + should be used when the information being plotted has a critical + middle value, such as topography or when the data deviates around + zero. + +3. Qualitative: often are miscellaneous colors; should be used to + represent information which does not have ordering or + relationships. +""" + +# sphinx_gallery_thumbnail_number = 2 + +import numpy as np +import matplotlib as mpl +import matplotlib.pyplot as plt +from matplotlib import cm +from colorspacious import cspace_converter +from collections import OrderedDict + +cmaps = OrderedDict() + +############################################################################### +# Sequential +# ---------- +# +# For the Sequential plots, the lightness value increases monotonically through +# the colormaps. This is good. Some of the :math:`L^*` values in the colormaps +# span from 0 to 100 (binary and the other grayscale), and others start around +# :math:`L^*=20`. Those that have a smaller range of :math:`L^*` will accordingly +# have a smaller perceptual range. Note also that the :math:`L^*` function varies +# amongst the colormaps: some are approximately linear in :math:`L^*` and others +# are more curved. + +cmaps['Perceptually Uniform Sequential'] = ['viridis', 'plasma', + 'inferno', 'magma'] + +cmaps['Sequential'] = [ + 'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds', + 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', + 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn'] + +############################################################################### +# Sequential2 +# ----------- +# +# Many of the :math:`L^*` values from the Sequential2 plots are monotonically +# increasing, but some (autumn, cool, spring, and winter) plateau or even go both +# up and down in :math:`L^*` space. Others (afmhot, copper, gist_heat, and hot) +# have kinks in the :math:`L^*` functions. Data that is being represented in a +# region of the colormap that is at a plateau or kink will lead to a perception of +# banding of the data in those values in the colormap (see [mycarta-banding]_ for +# an excellent example of this). + +cmaps['Sequential (2)'] = [ + 'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink', + 'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia', + 'hot', 'afmhot', 'gist_heat', 'copper'] + +############################################################################### +# Diverging +# --------- +# +# For the Diverging maps, we want to have monotonically increasing :math:`L^*` +# values up to a maximum, which should be close to :math:`L^*=100`, followed by +# monotonically decreasing :math:`L^*` values. We are looking for approximately +# equal minimum :math:`L^*` values at opposite ends of the colormap. By these +# measures, BrBG and RdBu are good options. coolwarm is a good option, but it +# doesn't span a wide range of :math:`L^*` values (see grayscale section below). + +cmaps['Diverging'] = [ + 'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', + 'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic'] + +############################################################################### +# Qualitative +# ----------- +# +# Qualitative colormaps are not aimed at being perceptual maps, but looking at the +# lightness parameter can verify that for us. The :math:`L^*` values move all over +# the place throughout the colormap, and are clearly not monotonically increasing. +# These would not be good options for use as perceptual colormaps. + +cmaps['Qualitative'] = ['Pastel1', 'Pastel2', 'Paired', 'Accent', + 'Dark2', 'Set1', 'Set2', 'Set3', + 'tab10', 'tab20', 'tab20b', 'tab20c'] + +############################################################################### +# Miscellaneous +# ------------- +# +# Some of the miscellaneous colormaps have particular uses for which +# they have been created. For example, gist_earth, ocean, and terrain +# all seem to be created for plotting topography (green/brown) and water +# depths (blue) together. We would expect to see a divergence in these +# colormaps, then, but multiple kinks may not be ideal, such as in +# gist_earth and terrain. CMRmap was created to convert well to +# grayscale, though it does appear to have some small kinks in +# :math:`L^*`. cubehelix was created to vary smoothly in both lightness +# and hue, but appears to have a small hump in the green hue area. +# +# The often-used jet colormap is included in this set of colormaps. We can see +# that the :math:`L^*` values vary widely throughout the colormap, making it a +# poor choice for representing data for viewers to see perceptually. See an +# extension on this idea at [mycarta-jet]_. + +cmaps['Miscellaneous'] = [ + 'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern', + 'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg', 'hsv', + 'gist_rainbow', 'rainbow', 'jet', 'nipy_spectral', 'gist_ncar'] + +############################################################################### +# .. _color-colormaps_reference: +# +# First, we'll show the range of each colormap. Note that some seem +# to change more "quickly" than others. + +nrows = max(len(cmap_list) for cmap_category, cmap_list in cmaps.items()) +gradient = np.linspace(0, 1, 256) +gradient = np.vstack((gradient, gradient)) + + +def plot_color_gradients(cmap_category, cmap_list, nrows): + fig, axes = plt.subplots(nrows=nrows) + fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99) + axes[0].set_title(cmap_category + ' colormaps', fontsize=14) + + for ax, name in zip(axes, cmap_list): + ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(name)) + pos = list(ax.get_position().bounds) + x_text = pos[0] - 0.01 + y_text = pos[1] + pos[3]/2. + fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10) + + # Turn off *all* ticks & spines, not just the ones with colormaps. + for ax in axes: + ax.set_axis_off() + + +for cmap_category, cmap_list in cmaps.items(): + plot_color_gradients(cmap_category, cmap_list, nrows) + +plt.show() + +############################################################################### +# Lightness of matplotlib colormaps +# ================================= +# +# Here we examine the lightness values of the matplotlib colormaps. +# Note that some documentation on the colormaps is available +# ([list-colormaps]_). + +mpl.rcParams.update({'font.size': 12}) + +# Number of colormap per subplot for particular cmap categories +_DSUBS = {'Perceptually Uniform Sequential': 4, 'Sequential': 6, + 'Sequential (2)': 6, 'Diverging': 6, 'Qualitative': 4, + 'Miscellaneous': 6} + +# Spacing between the colormaps of a subplot +_DC = {'Perceptually Uniform Sequential': 1.4, 'Sequential': 0.7, + 'Sequential (2)': 1.4, 'Diverging': 1.4, 'Qualitative': 1.4, + 'Miscellaneous': 1.4} + +# Indices to step through colormap +x = np.linspace(0.0, 1.0, 100) + +# Do plot +for cmap_category, cmap_list in cmaps.items(): + + # Do subplots so that colormaps have enough space. + # Default is 6 colormaps per subplot. + dsub = _DSUBS.get(cmap_category, 6) + nsubplots = int(np.ceil(len(cmap_list) / float(dsub))) + + # squeeze=False to handle similarly the case of a single subplot + fig, axes = plt.subplots(nrows=nsubplots, squeeze=False, + figsize=(7, 2.6*nsubplots)) + + for i, ax in enumerate(axes.flat): + + locs = [] # locations for text labels + + for j, cmap in enumerate(cmap_list[i*dsub:(i+1)*dsub]): + + # Get RGB values for colormap and convert the colormap in + # CAM02-UCS colorspace. lab[0, :, 0] is the lightness. + rgb = cm.get_cmap(cmap)(x)[np.newaxis, :, :3] + lab = cspace_converter("sRGB1", "CAM02-UCS")(rgb) + + # Plot colormap L values. Do separately for each category + # so each plot can be pretty. To make scatter markers change + # color along plot: + # http://stackoverflow.com/questions/8202605/matplotlib-scatterplot-colour-as-a-function-of-a-third-variable + + if cmap_category == 'Sequential': + # These colormaps all start at high lightness but we want them + # reversed to look nice in the plot, so reverse the order. + y_ = lab[0, ::-1, 0] + c_ = x[::-1] + else: + y_ = lab[0, :, 0] + c_ = x + + dc = _DC.get(cmap_category, 1.4) # cmaps horizontal spacing + ax.scatter(x + j*dc, y_, c=c_, cmap=cmap, s=300, linewidths=0.0) + + # Store locations for colormap labels + if cmap_category in ('Perceptually Uniform Sequential', + 'Sequential'): + locs.append(x[-1] + j*dc) + elif cmap_category in ('Diverging', 'Qualitative', + 'Miscellaneous', 'Sequential (2)'): + locs.append(x[int(x.size/2.)] + j*dc) + + # Set up the axis limits: + # * the 1st subplot is used as a reference for the x-axis limits + # * lightness values goes from 0 to 100 (y-axis limits) + ax.set_xlim(axes[0, 0].get_xlim()) + ax.set_ylim(0.0, 100.0) + + # Set up labels for colormaps + ax.xaxis.set_ticks_position('top') + ticker = mpl.ticker.FixedLocator(locs) + ax.xaxis.set_major_locator(ticker) + formatter = mpl.ticker.FixedFormatter(cmap_list[i*dsub:(i+1)*dsub]) + ax.xaxis.set_major_formatter(formatter) + ax.xaxis.set_tick_params(rotation=50) + + ax.set_xlabel(cmap_category + ' colormaps', fontsize=14) + fig.text(0.0, 0.55, 'Lightness $L^*$', fontsize=12, + transform=fig.transFigure, rotation=90) + + fig.tight_layout(h_pad=0.0, pad=1.5) + plt.show() + + +############################################################################### +# Grayscale conversion +# ==================== +# +# It is important to pay attention to conversion to grayscale for color +# plots, since they may be printed on black and white printers. If not +# carefully considered, your readers may end up with indecipherable +# plots because the grayscale changes unpredictably through the +# colormap. +# +# Conversion to grayscale is done in many different ways [bw]_. Some of the better +# ones use a linear combination of the rgb values of a pixel, but weighted +# according to how we perceive color intensity. A nonlinear method of conversion +# to grayscale is to use the :math:`L^*` values of the pixels. In general, similar +# principles apply for this question as they do for presenting one's information +# perceptually; that is, if a colormap is chosen that is monotonically increasing +# in :math:`L^*` values, it will print in a reasonable manner to grayscale. +# +# With this in mind, we see that the Sequential colormaps have reasonable +# representations in grayscale. Some of the Sequential2 colormaps have decent +# enough grayscale representations, though some (autumn, spring, summer, winter) +# have very little grayscale change. If a colormap like this was used in a plot +# and then the plot was printed to grayscale, a lot of the information may map to +# the same gray values. The Diverging colormaps mostly vary from darker gray on +# the outer edges to white in the middle. Some (PuOr and seismic) have noticably +# darker gray on one side than the other and therefore are not very symmetric. +# coolwarm has little range of gray scale and would print to a more uniform plot, +# losing a lot of detail. Note that overlaid, labeled contours could help +# differentiate between one side of the colormap vs. the other since color cannot +# be used once a plot is printed to grayscale. Many of the Qualitative and +# Miscellaneous colormaps, such as Accent, hsv, and jet, change from darker to +# lighter and back to darker gray throughout the colormap. This would make it +# impossible for a viewer to interpret the information in a plot once it is +# printed in grayscale. + +mpl.rcParams.update({'font.size': 14}) + +# Indices to step through colormap. +x = np.linspace(0.0, 1.0, 100) + +gradient = np.linspace(0, 1, 256) +gradient = np.vstack((gradient, gradient)) + + +def plot_color_gradients(cmap_category, cmap_list): + fig, axes = plt.subplots(nrows=len(cmap_list), ncols=2) + fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99, + wspace=0.05) + fig.suptitle(cmap_category + ' colormaps', fontsize=14, y=1.0, x=0.6) + + for ax, name in zip(axes, cmap_list): + + # Get RGB values for colormap. + rgb = cm.get_cmap(plt.get_cmap(name))(x)[np.newaxis,:,:3] + + # Get colormap in CAM02-UCS colorspace. We want the lightness. + lab = cspace_converter("sRGB1", "CAM02-UCS")(rgb) + L = lab[0,:,0] + L = np.float32(np.vstack((L, L, L))) + + ax[0].imshow(gradient, aspect='auto', cmap=plt.get_cmap(name)) + ax[1].imshow(L, aspect='auto', cmap='binary_r', vmin=0., vmax=100.) + pos = list(ax[0].get_position().bounds) + x_text = pos[0] - 0.01 + y_text = pos[1] + pos[3]/2. + fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10) + + # Turn off *all* ticks & spines, not just the ones with colormaps. + for ax in axes.flat: + ax.set_axis_off() + + plt.show() + + +for cmap_category, cmap_list in cmaps.items(): + + plot_color_gradients(cmap_category, cmap_list) + +############################################################################### +# Color vision deficiencies +# ========================= +# +# There is a lot of information available about color blindness (*e.g.*, +# [colorblindness]_). Additionally, there are tools available to convert images to +# how they look for different types of color vision deficiencies (*e.g.*, +# [vischeck]_). +# +# The most common form of color vision deficiency involves differentiating between +# red and green. Thus, avoiding colormaps with both red and green will avoid many +# problems in general. +# +# +# References +# ========== +# +# .. [colorcet] https://github.com/bokeh/colorcet +# .. [Ware] http://ccom.unh.edu/sites/default/files/publications/Ware_1988_CGA_Color_sequences_univariate_maps.pdf +# .. [Moreland] http://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf +# .. [list-colormaps] https://gist.github.com/endolith/2719900#id7 +# .. [mycarta-banding] https://mycarta.wordpress.com/2012/10/14/the-rainbow-is-deadlong-live-the-rainbow-part-4-cie-lab-heated-body/ +# .. [mycarta-jet] https://mycarta.wordpress.com/2012/10/06/the-rainbow-is-deadlong-live-the-rainbow-part-3/ +# .. [mycarta-lablinear] https://mycarta.wordpress.com/2012/12/06/the-rainbow-is-deadlong-live-the-rainbow-part-5-cie-lab-linear-l-rainbow/ +# .. [mycarta-cubelaw] https://mycarta.wordpress.com/2013/02/21/perceptual-rainbow-palette-the-method/ +# .. [bw] http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/ +# .. [colorblindness] http://www.color-blindness.com/ +# .. [vischeck] http://www.vischeck.com/vischeck/ +# .. [IBM] http://www.research.ibm.com/people/l/lloydt/color/color.HTM diff --git a/tutorials/colors/colors.py b/tutorials/colors/colors.py new file mode 100644 index 000000000000..5f5c3d4dce05 --- /dev/null +++ b/tutorials/colors/colors.py @@ -0,0 +1,113 @@ +""" +***************** +Specifying Colors +***************** + +In almost all places in matplotlib where a color can be specified by the user +it can be provided as: + +* an RGB or RGBA tuple of float values in ``[0, 1]`` + (e.g., ``(0.1, 0.2, 0.5)`` or ``(0.1, 0.2, 0.5, 0.3)``) +* a hex RGB or RGBA string (e.g., ``'#0F0F0F'`` or ``'#0F0F0F0F'``) +* a string representation of a float value in ``[0, 1]`` + inclusive for gray level (e.g., ``'0.5'``) +* one of ``{'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w'}`` +* a X11/CSS4 color name +* a name from the `xkcd color survey `__ + prefixed with ``'xkcd:'`` (e.g., ``'xkcd:sky blue'``) +* one of ``{'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9'}`` +* one of ``{'tab:blue', 'tab:orange', 'tab:green', + 'tab:red', 'tab:purple', 'tab:brown', 'tab:pink', + 'tab:gray', 'tab:olive', 'tab:cyan'}`` which are the Tableau Colors from the + 'T10' categorical palette (which is the default color cycle). + +All string specifications of color are case-insensitive. + + +``'CN'`` color selection +------------------------ + +Color can be specified by a string matching the regex ``C[0-9]``. +This can be passed any place that a color is currently accepted and +can be used as a 'single character color' in format-string to +`matplotlib.Axes.plot`. + +The single digit is the index into the default property cycle +(``matplotlib.rcParams['axes.prop_cycle']``). If the property cycle does not +include ``'color'`` then black is returned. The color is evaluated when the +artist is created. For example, +""" + + +import numpy as np +import matplotlib.pyplot as plt +import matplotlib as mpl + +th = np.linspace(0, 2*np.pi, 128) + + +def demo(sty): + mpl.style.use(sty) + fig, ax = plt.subplots(figsize=(3, 3)) + + ax.set_title('style: {!r}'.format(sty), color='C0') + + ax.plot(th, np.cos(th), 'C1', label='C1') + ax.plot(th, np.sin(th), 'C2', label='C2') + ax.legend() + +demo('default') +demo('seaborn') + +############################################################################### +# will use the first color for the title and then plot using the second +# and third colors of each style's ``mpl.rcParams['axes.prop_cycle']``. +# +# +# xkcd v X11/CSS4 +# --------------- +# +# The xkcd colors are derived from a user survey conducted by the +# webcomic xkcd. `Details of the survey are available on the xkcd blog +# `__. +# +# Out of 148 colors in the CSS color list, there are 95 name collisions +# between the X11/CSS4 names and the xkcd names, all but 3 of which have +# different hex values. For example ``'blue'`` maps to ``'#0000FF'`` +# where as ``'xkcd:blue'`` maps to ``'#0343DF'``. Due to these name +# collisions all of the xkcd colors have ``'xkcd:'`` prefixed. As noted in +# the blog post, while it might be interesting to re-define the X11/CSS4 names +# based on such a survey, we do not do so unilaterally. +# +# The name collisions are shown in the table below; the color names +# where the hex values agree are shown in bold. + +import matplotlib._color_data as mcd +import matplotlib.patches as mpatch + +overlap = {name for name in mcd.CSS4_COLORS + if "xkcd:" + name in mcd.XKCD_COLORS} + +fig = plt.figure(figsize=[4.8, 16]) +ax = fig.add_axes([0, 0, 1, 1]) + +for j, n in enumerate(sorted(overlap, reverse=True)): + weight = None + cn = mcd.CSS4_COLORS[n] + xkcd = mcd.XKCD_COLORS["xkcd:" + n].upper() + if cn == xkcd: + weight = 'bold' + + r1 = mpatch.Rectangle((0, j), 1, 1, color=cn) + r2 = mpatch.Rectangle((1, j), 1, 1, color=xkcd) + txt = ax.text(2, j+.5, ' ' + n, va='center', fontsize=10, + weight=weight) + ax.add_patch(r1) + ax.add_patch(r2) + ax.axhline(j, color='k') + +ax.text(.5, j + 1.5, 'X11', ha='center', va='center') +ax.text(1.5, j + 1.5, 'xkcd', ha='center', va='center') +ax.set_xlim(0, 3) +ax.set_ylim(0, j + 2) +ax.axis('off') diff --git a/tutorials/text/README.txt b/tutorials/text/README.txt new file mode 100644 index 000000000000..8ef15ce1970c --- /dev/null +++ b/tutorials/text/README.txt @@ -0,0 +1,10 @@ +.. _tutorials-text: + +Text +==== + +matplotlib has extensive text support, including support for +mathematical expressions, truetype support for raster and +vector outputs, newline separated text with arbitrary +rotations, and unicode support. These tutorials cover +the basics of working with text in Matplotlib. diff --git a/doc/users/annotations.rst b/tutorials/text/annotations.py similarity index 85% rename from doc/users/annotations.rst rename to tutorials/text/annotations.py index 6de5098e5cfe..1fc6e750dd1b 100644 --- a/doc/users/annotations.rst +++ b/tutorials/text/annotations.py @@ -1,6 +1,8 @@ -============ - Annotation -============ +""" +Annotations +=========== + +Annotating text with Matplotlib. .. contents:: Table of Contents :depth: 3 @@ -19,8 +21,8 @@ ``xy`` and the location of the text ``xytext``. Both of these arguments are ``(x,y)`` tuples. -.. figure:: ../gallery/pyplots/images/sphx_glr_annotation_basic_001.png - :target: ../gallery/pyplots/annotation_basic.html +.. figure:: ../../gallery/pyplots/images/sphx_glr_annotation_basic_001.png + :target: ../../gallery/pyplots/annotation_basic.html :align: center :scale: 50 @@ -83,8 +85,8 @@ ``fontsize`` are passed from `~matplotlib.Axes.annotate` to the ``Text`` instance. -.. figure:: ../gallery/pyplots/images/sphx_glr_annotation_polar_001.png - :target: ../gallery/pyplots/annotation_polar.html +.. figure:: ../../gallery/pyplots/images/sphx_glr_annotation_polar_001.png + :target: ../../gallery/pyplots/annotation_polar.html :align: center :scale: 50 @@ -92,7 +94,7 @@ For more on all the wild and wonderful things you can do with annotations, including fancy arrows, see :ref:`plotting-guide-annotation` -and :ref:`pylab_examples-annotation_demo`. +and :ref:`sphx_glr_gallery_pylab_examples_annotation_demo.py`. Do not proceed unless you have already read :ref:`annotations-tutorial`, @@ -110,8 +112,8 @@ Let's start with a simple example. -.. figure:: ../gallery/userdemo/images/sphx_glr_annotate_text_arrow_001.png - :target: ../gallery/userdemo/annotate_text_arrow.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_annotate_text_arrow_001.png + :target: ../../gallery/userdemo/annotate_text_arrow.html :align: center :scale: 50 @@ -156,8 +158,8 @@ Square ``square`` pad=0.3 ========== ============== ========================== -.. figure:: ../gallery/pylab_examples/images/sphx_glr_fancybox_demo2_001.png - :target: ../gallery/pylab_examples/fancybox_demo2.html +.. figure:: ../../gallery/pylab_examples/images/sphx_glr_fancybox_demo2_001.png + :target: ../../gallery/pylab_examples/fancybox_demo2.html :align: center :scale: 50 @@ -202,8 +204,8 @@ connectionstyle="arc3"), ) -.. figure:: ../gallery/userdemo/images/sphx_glr_annotate_simple01_001.png - :target: ../gallery/userdemo/annotate_simple01.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_annotate_simple01_001.png + :target: ../../gallery/userdemo/annotate_simple01.html :align: center :scale: 50 @@ -224,8 +226,8 @@ ``arrowstyle`` key value. -.. figure:: ../gallery/userdemo/images/sphx_glr_annotate_explain_001.png - :target: ../gallery/userdemo/annotate_explain.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_annotate_explain_001.png + :target: ../../gallery/userdemo/annotate_explain.html :align: center :scale: 50 @@ -254,8 +256,8 @@ example below. (Warning : The behavior of the ``bar`` style is currently not well defined, it may be changed in the future). -.. figure:: ../gallery/userdemo/images/sphx_glr_connectionstyle_demo_001.png - :target: ../gallery/userdemo/connectionstyle_demo.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_connectionstyle_demo_001.png + :target: ../../gallery/userdemo/connectionstyle_demo.html :align: center :scale: 50 @@ -282,8 +284,8 @@ ``wedge`` tail_width=0.3,shrink_factor=0.5 ========== ============================================= -.. figure:: ../gallery/pylab_examples/images/sphx_glr_fancyarrow_demo_001.png - :target: ../gallery/pylab_examples/fancyarrow_demo.html +.. figure:: ../../gallery/pylab_examples/images/sphx_glr_fancyarrow_demo_001.png + :target: ../../gallery/pylab_examples/fancyarrow_demo.html :align: center :scale: 50 @@ -297,8 +299,8 @@ If the annotation string is given, the patchA is set to the bbox patch of the text by default. -.. figure:: ../gallery/userdemo/images/sphx_glr_annotate_simple02_001.png - :target: ../gallery/userdemo/annotate_simple02.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_annotate_simple02_001.png + :target: ../../gallery/userdemo/annotate_simple02.html :align: center :scale: 50 @@ -307,8 +309,8 @@ As in the text command, a box around the text can be drawn using the ``bbox`` argument. -.. figure:: ../gallery/userdemo/images/sphx_glr_annotate_simple03_001.png - :target: ../gallery/userdemo/annotate_simple03.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_annotate_simple03_001.png + :target: ../../gallery/userdemo/annotate_simple03.html :align: center :scale: 50 @@ -319,8 +321,8 @@ are normalized to the extent of the text. For example, (0,0) means lower-left corner and (1,1) means top-right. -.. figure:: ../gallery/userdemo/images/sphx_glr_annotate_simple04_001.png - :target: ../gallery/userdemo/annotate_simple04.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_annotate_simple04_001.png + :target: ../../gallery/userdemo/annotate_simple04.html :align: center :scale: 50 @@ -345,8 +347,8 @@ ax.add_artist(at) -.. figure:: ../gallery/userdemo/images/sphx_glr_anchored_box01_001.png - :target: ../gallery/userdemo/anchored_box01.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_anchored_box01_001.png + :target: ../../gallery/userdemo/anchored_box01.html :align: center :scale: 50 @@ -379,8 +381,8 @@ artists are interpreted as a pixel coordinate, i.e., the radius of the circles in above example are 10 pixels and 5 pixels, respectively. -.. figure:: ../gallery/userdemo/images/sphx_glr_anchored_box02_001.png - :target: ../gallery/userdemo/anchored_box02.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_anchored_box02_001.png + :target: ../../gallery/userdemo/anchored_box02.html :align: center :scale: 50 @@ -402,8 +404,8 @@ corresponding to 0.1 and 0.4 in data coordinateing and will be automatically scaled when the view limits of the axes change. -.. figure:: ../gallery/userdemo/images/sphx_glr_anchored_box03_001.png - :target: ../gallery/userdemo/anchored_box03.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_anchored_box03_001.png + :target: ../../gallery/userdemo/anchored_box03.html :align: center :scale: 50 @@ -413,8 +415,8 @@ HPacker and VPacker, you can have an arrangement(?) of artist as in the legend (as a matter of fact, this is how the legend is created). -.. figure:: ../gallery/userdemo/images/sphx_glr_anchored_box04_001.png - :target: ../gallery/userdemo/anchored_box04.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_anchored_box04_001.png + :target: ../../gallery/userdemo/anchored_box04.html :align: center :scale: 50 @@ -458,8 +460,8 @@ bbox=dict(boxstyle="round", fc="w"), arrowprops=dict(arrowstyle="->")) - .. figure:: ../gallery/userdemo/images/sphx_glr_annotate_simple_coord01_001.png - :target: ../gallery/userdemo/annotate_simple_coord01.html + .. figure:: ../../gallery/userdemo/images/sphx_glr_annotate_simple_coord01_001.png + :target: ../../gallery/userdemo/annotate_simple_coord01.html :align: center :scale: 50 @@ -493,8 +495,8 @@ 0.5 is in data coordinates, and 1 is in normalized axes coordinates. You may use an artist or transform as with a tuple. For example, - .. figure:: ../gallery/userdemo/images/sphx_glr_annotate_simple_coord02_001.png - :target: ../gallery/userdemo/annotate_simple_coord02.html + .. figure:: ../../gallery/userdemo/images/sphx_glr_annotate_simple_coord02_001.png + :target: ../../gallery/userdemo/annotate_simple_coord02.html :align: center :scale: 50 @@ -504,14 +506,14 @@ annotated point but from some other point. :class:`~matplotlib.text.OffsetFrom` is a helper class for such cases. - .. figure:: ../gallery/userdemo/images/sphx_glr_annotate_simple_coord03_001.png - :target: ../gallery/userdemo/annotate_simple_coord03.html + .. figure:: ../../gallery/userdemo/images/sphx_glr_annotate_simple_coord03_001.png + :target: ../../gallery/userdemo/annotate_simple_coord03.html :align: center :scale: 50 Annotation with Simple Coordinates 3 - You may take a look at this example :ref:`pylab_examples-annotation_demo3`. + You may take a look at this example :ref:`sphx_glr_gallery_pylab_examples_annotation_demo3.py`. Using ConnectorPatch -------------------- @@ -529,8 +531,8 @@ The above code connects point xy in the data coordinates of ``ax1`` to point xy in the data coordinates of ``ax2``. Here is a simple example. -.. figure:: ../gallery/userdemo/images/sphx_glr_connect_simple01_001.png - :target: ../gallery/userdemo/connect_simple01.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_connect_simple01_001.png + :target: ../../gallery/userdemo/connect_simple01.html :align: center :scale: 50 @@ -554,8 +556,8 @@ straight forward. -.. figure:: ../gallery/pylab_examples/images/sphx_glr_axes_zoom_effect_001.png - :target: ../gallery/pylab_examples/axes_zoom_effect.html +.. figure:: ../../gallery/pylab_examples/images/sphx_glr_axes_zoom_effect_001.png + :target: ../../gallery/pylab_examples/axes_zoom_effect.html :align: center :scale: 50 @@ -570,21 +572,21 @@ def __call__(self, x0, y0, width, height, mutation_size, aspect_ratio=1.): - """ + ''' Given the location and size of the box, return the path of the box around it. - *x0*, *y0*, *width*, *height* : location and size of the box - *mutation_size* : a reference scale for the mutation. - *aspect_ratio* : aspect-ratio for the mutation. - """ + ''' path = ... return path Here is a complete example. -.. figure:: ../gallery/userdemo/images/sphx_glr_custom_boxstyle01_001.png - :target: ../gallery/userdemo/custom_boxstyle01.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_custom_boxstyle01_001.png + :target: ../../gallery/userdemo/custom_boxstyle01.html :align: center :scale: 50 @@ -593,8 +595,8 @@ def __call__(self, x0, y0, width, height, mutation_size, However, it is recommended that you derive from the matplotlib.patches.BoxStyle._Base as demonstrated below. -.. figure:: ../gallery/userdemo/images/sphx_glr_custom_boxstyle02_001.png - :target: ../gallery/userdemo/custom_boxstyle02.html +.. figure:: ../../gallery/userdemo/images/sphx_glr_custom_boxstyle02_001.png + :target: ../../gallery/userdemo/custom_boxstyle02.html :align: center :scale: 50 @@ -604,21 +606,4 @@ def __call__(self, x0, y0, width, height, mutation_size, Similarly, you can define a custom ConnectionStyle and a custom ArrowStyle. See the source code of ``lib/matplotlib/patches.py`` and check how each style class is defined. - - - - - - - - - - - - - - - - - - +""" diff --git a/tutorials/text/mathtext.py b/tutorials/text/mathtext.py new file mode 100644 index 000000000000..ab4f93de75f4 --- /dev/null +++ b/tutorials/text/mathtext.py @@ -0,0 +1,350 @@ +""" +Writing mathematical expressions +================================ + +An introduction to writing mathematical expressions in Matplotlib. + +You can use a subset TeX markup in any matplotlib text string by +placing it inside a pair of dollar signs ($). + +Note that you do not need to have TeX installed, since matplotlib +ships its own TeX expression parser, layout engine and fonts. The +layout engine is a fairly direct adaptation of the layout algorithms +in Donald Knuth's TeX, so the quality is quite good (matplotlib also +provides a ``usetex`` option for those who do want to call out to TeX +to generate their text (see :ref:`sphx_glr_tutorials_text_usetex.py`). +""" + +# Any text element can use math text. You should use raw strings (precede the +# quotes with an ``'r'``), and surround the math text with dollar signs ($), as in +# TeX. Regular text and mathtext can be interleaved within the same string. +# Mathtext can use DejaVu Sans (default), DejaVu Serif, the Computer Modern fonts +# (from (La)TeX), `STIX `_ fonts (with are designed +# to blend well with Times), or a Unicode font that you provide. The mathtext +# font can be selected with the customization variable ``mathtext.fontset`` (see +# :ref:`sphx_glr_tutorials_01_introductory_customizing.py`) +# +# .. note:: +# On `"narrow" `_ builds +# of Python, if you use the STIX fonts you should also set +# ``ps.fonttype`` and ``pdf.fonttype`` to 3 (the default), not 42. +# Otherwise `some characters will not be visible +# `_. +# +# Here is a simple example:: + +# # plain text +# plt.title('alpha > beta') +# +# produces "alpha > beta". +# +# Whereas this:: +# +# # math text +# plt.title(r'$\alpha > \beta$') +# +# produces ":math:`\alpha > \beta`". +# +# .. note:: +# Mathtext should be placed between a pair of dollar signs ($). To +# make it easy to display monetary values, e.g., "$100.00", if a +# single dollar sign is present in the entire string, it will be +# displayed verbatim as a dollar sign. This is a small change from +# regular TeX, where the dollar sign in non-math text would have to +# be escaped ('\\\$'). +# +# .. note:: +# While the syntax inside the pair of dollar signs ($) aims to be +# TeX-like, the text outside does not. In particular, characters +# such as:: +# +# # $ % & ~ _ ^ \ { } \( \) \[ \] +# +# have special meaning outside of math mode in TeX. Therefore, these +# characters will behave differently depending on the rcParam +# ``text.usetex`` flag. See the :ref:`usetex tutorial +# ` for more information. +# +# Subscripts and superscripts +# --------------------------- +# +# To make subscripts and superscripts, use the ``'_'`` and ``'^'`` symbols:: +# +# r'$\alpha_i > \beta_i$' +# +# .. math:: +# +# \alpha_i > \beta_i +# +# Some symbols automatically put their sub/superscripts under and over +# the operator. For example, to write the sum of :math:`x_i` from :math:`0` to +# :math:`\infty`, you could do:: +# +# r'$\sum_{i=0}^\infty x_i$' +# +# .. math:: +# +# \sum_{i=0}^\infty x_i +# +# Fractions, binomials and stacked numbers +# ---------------------------------------- +# +# Fractions, binomials and stacked numbers can be created with the +# ``\frac{}{}``, ``\binom{}{}`` and ``\stackrel{}{}`` commands, +# respectively:: +# +# r'$\frac{3}{4} \binom{3}{4} \stackrel{3}{4}$' +# +# produces +# +# .. math:: +# +# \frac{3}{4} \binom{3}{4} \stackrel{3}{4} +# +# Fractions can be arbitrarily nested:: +# +# r'$\frac{5 - \frac{1}{x}}{4}$' +# +# produces +# +# .. math:: +# +# \frac{5 - \frac{1}{x}}{4} +# +# Note that special care needs to be taken to place parentheses and brackets around +# fractions. Doing things the obvious way produces brackets that are +# too small:: +# +# r'$(\frac{5 - \frac{1}{x}}{4})$' +# +# .. math :: +# +# (\frac{5 - \frac{1}{x}}{4}) +# +# The solution is to precede the bracket with ``\left`` and ``\right`` +# to inform the parser that those brackets encompass the entire object.:: +# +# r'$\left(\frac{5 - \frac{1}{x}}{4}\right)$' +# +# .. math :: +# +# \left(\frac{5 - \frac{1}{x}}{4}\right) +# +# Radicals +# -------- +# +# Radicals can be produced with the ``\sqrt[]{}`` command. For example:: +# +# r'$\sqrt{2}$' +# +# .. math :: +# +# \sqrt{2} +# +# Any base can (optionally) be provided inside square brackets. Note +# that the base must be a simple expression, and can not contain layout +# commands such as fractions or sub/superscripts:: +# +# r'$\sqrt[3]{x}$' +# +# .. math :: +# +# \sqrt[3]{x} +# +# Fonts +# ----- +# +# The default font is *italics* for mathematical symbols. +# +# .. note:: +# +# This default can be changed using the ``mathtext.default`` rcParam. +# This is useful, for example, to use the same font as regular +# non-math text for math text, by setting it to ``regular``. +# +# To change fonts, e.g., to write "sin" in a Roman font, enclose the text +# in a font command:: +# +# r'$s(t) = \mathcal{A}\mathrm{sin}(2 \omega t)$' +# +# .. math:: +# +# s(t) = \mathcal{A}\mathrm{sin}(2 \omega t) +# +# More conveniently, many commonly used function names that are typeset in a +# Roman font have shortcuts. So the expression above could be written +# as follows:: +# +# r'$s(t) = \mathcal{A}\sin(2 \omega t)$' +# +# .. math:: +# +# s(t) = \mathcal{A}\sin(2 \omega t) +# +# Here "s" and "t" are variable in italics font (default), "sin" is in +# Roman font, and the amplitude "A" is in calligraphy font. Note in the +# example above the caligraphy ``A`` is squished into the ``sin``. You +# can use a spacing command to add a little whitespace between them:: +# +# s(t) = \mathcal{A}\/\sin(2 \omega t) +# +# .. math:: +# +# s(t) = \mathcal{A}\/\sin(2 \omega t) +# +# The choices available with all fonts are: +# +# ============================ ================================== +# Command Result +# ============================ ================================== +# ``\mathrm{Roman}`` :math:`\mathrm{Roman}` +# ``\mathit{Italic}`` :math:`\mathit{Italic}` +# ``\mathtt{Typewriter}`` :math:`\mathtt{Typewriter}` +# ``\mathcal{CALLIGRAPHY}`` :math:`\mathcal{CALLIGRAPHY}` +# ============================ ================================== +# +# .. role:: math-stix(math) +# :fontset: stix +# +# When using the `STIX `_ fonts, you also have the choice of: +# +# ====================================== ========================================= +# Command Result +# ====================================== ========================================= +# ``\mathbb{blackboard}`` :math-stix:`\mathbb{blackboard}` +# ``\mathrm{\mathbb{blackboard}}`` :math-stix:`\mathrm{\mathbb{blackboard}}` +# ``\mathfrak{Fraktur}`` :math-stix:`\mathfrak{Fraktur}` +# ``\mathsf{sansserif}`` :math-stix:`\mathsf{sansserif}` +# ``\mathrm{\mathsf{sansserif}}`` :math-stix:`\mathrm{\mathsf{sansserif}}` +# ====================================== ========================================= +# +# .. htmlonly:: +# +# ====================================== ========================================= +# ``\mathcircled{circled}`` :math-stix:`\mathcircled{circled}` +# ====================================== ========================================= +# +# There are also three global "font sets" to choose from, which are +# selected using the ``mathtext.fontset`` parameter in +# :ref:`matplotlibrc `. +# +# ``cm``: **Computer Modern (TeX)** +# +# .. image:: ../../_static/cm_fontset.png +# +# ``stix``: **STIX** (designed to blend well with Times) +# +# .. image:: ../../_static/stix_fontset.png +# +# ``stixsans``: **STIX sans-serif** +# +# .. image:: ../../_static/stixsans_fontset.png +# +# Additionally, you can use ``\mathdefault{...}`` or its alias +# ``\mathregular{...}`` to use the font used for regular text outside of +# mathtext. There are a number of limitations to this approach, most +# notably that far fewer symbols will be available, but it can be useful +# to make math expressions blend well with other text in the plot. +# +# Custom fonts +# ~~~~~~~~~~~~ +# +# mathtext also provides a way to use custom fonts for math. This +# method is fairly tricky to use, and should be considered an +# experimental feature for patient users only. By setting the rcParam +# ``mathtext.fontset`` to ``custom``, you can then set the following +# parameters, which control which font file to use for a particular set +# of math characters. +# +# ============================== ================================= +# Parameter Corresponds to +# ============================== ================================= +# ``mathtext.it`` ``\mathit{}`` or default italic +# ``mathtext.rm`` ``\mathrm{}`` Roman (upright) +# ``mathtext.tt`` ``\mathtt{}`` Typewriter (monospace) +# ``mathtext.bf`` ``\mathbf{}`` bold italic +# ``mathtext.cal`` ``\mathcal{}`` calligraphic +# ``mathtext.sf`` ``\mathsf{}`` sans-serif +# ============================== ================================= +# +# Each parameter should be set to a fontconfig font descriptor (as +# defined in the yet-to-be-written font chapter). +# +# .. TODO: Link to font chapter +# +# The fonts used should have a Unicode mapping in order to find any +# non-Latin characters, such as Greek. If you want to use a math symbol +# that is not contained in your custom fonts, you can set the rcParam +# ``mathtext.fallback_to_cm`` to ``True`` which will cause the mathtext +# system to use characters from the default Computer Modern fonts +# whenever a particular character can not be found in the custom font. +# +# Note that the math glyphs specified in Unicode have evolved over time, +# and many fonts may not have glyphs in the correct place for mathtext. +# +# Accents +# ------- +# +# An accent command may precede any symbol to add an accent above it. +# There are long and short forms for some of them. +# +# ============================== ================================= +# Command Result +# ============================== ================================= +# ``\acute a`` or ``\'a`` :math:`\acute a` +# ``\bar a`` :math:`\bar a` +# ``\breve a`` :math:`\breve a` +# ``\ddot a`` or ``\''a`` :math:`\ddot a` +# ``\dot a`` or ``\.a`` :math:`\dot a` +# ``\grave a`` or ``\`a`` :math:`\grave a` +# ``\hat a`` or ``\^a`` :math:`\hat a` +# ``\tilde a`` or ``\~a`` :math:`\tilde a` +# ``\vec a`` :math:`\vec a` +# ``\overline{abc}`` :math:`\overline{abc}` +# ============================== ================================= +# +# In addition, there are two special accents that automatically adjust +# to the width of the symbols below: +# +# ============================== ================================= +# Command Result +# ============================== ================================= +# ``\widehat{xyz}`` :math:`\widehat{xyz}` +# ``\widetilde{xyz}`` :math:`\widetilde{xyz}` +# ============================== ================================= +# +# Care should be taken when putting accents on lower-case i's and j's. +# Note that in the following ``\imath`` is used to avoid the extra dot +# over the i:: +# +# r"$\hat i\ \ \hat \imath$" +# +# .. math:: +# +# \hat i\ \ \hat \imath +# +# Symbols +# ------- +# +# You can also use a large number of the TeX symbols, as in ``\infty``, +# ``\leftarrow``, ``\sum``, ``\int``. +# +# .. math_symbol_table:: +# +# If a particular symbol does not have a name (as is true of many of the +# more obscure symbols in the STIX fonts), Unicode characters can +# also be used:: +# +# ur'$\u23ce$' +# +# Example +# ------- +# +# Here is an example illustrating many of these features in context. +# +# .. figure:: ../../gallery/pyplots/images/sphx_glr_pyplot_mathtext_001.png +# :target: ../../gallery/pyplots/pyplot_mathtext.html +# :align: center +# :scale: 50 +# +# Pyplot Mathtext diff --git a/doc/users/pgf.rst b/tutorials/text/pgf.py similarity index 95% rename from doc/users/pgf.rst rename to tutorials/text/pgf.py index 7b3ce8771b5c..27415528e160 100644 --- a/doc/users/pgf.rst +++ b/tutorials/text/pgf.py @@ -1,9 +1,10 @@ -.. _pgf-tutorial: - +""" ********************************* Typesetting With XeLaTeX/LuaLaTeX ********************************* +How to typeset text with the ``pgf`` backend in Matplotlib. + Using the ``pgf`` backend, matplotlib can export figures as pgf drawing commands that can be processed with pdflatex, xelatex or lualatex. XeLaTeX and LuaLaTeX have full unicode support and can use any font that is installed in the operating @@ -70,7 +71,7 @@ When saving to ``.pgf``, the font configuration matplotlib used for the layout of the figure is included in the header of the text file. -.. literalinclude:: ../gallery/userdemo/pgf_fonts_sgskip.py +.. literalinclude:: ../../gallery/userdemo/pgf_fonts_sgskip.py :end-before: plt.savefig @@ -87,12 +88,12 @@ .. htmlonly:: - .. literalinclude:: ../gallery/userdemo/pgf_preamble_sgskip.py + .. literalinclude:: ../../gallery/userdemo/pgf_preamble_sgskip.py :end-before: plt.savefig .. latexonly:: - .. literalinclude:: ../gallery/userdemo/pgf_preamble_sgskip.py + .. literalinclude:: ../../gallery/userdemo/pgf_preamble_sgskip.py :end-before: import matplotlib.pyplot as plt @@ -106,7 +107,7 @@ ``'pdflatex'``. Please note that when selecting pdflatex the fonts and unicode handling must be configured in the preamble. -.. literalinclude:: ../gallery/userdemo/pgf_texsystem_sgskip.py +.. literalinclude:: ../../gallery/userdemo/pgf_texsystem_sgskip.py :end-before: plt.savefig @@ -169,3 +170,4 @@ .. _LaTeX: http://www.tug.org .. _TeXLive: http://www.tug.org/texlive/ +""" diff --git a/doc/users/text_intro.rst b/tutorials/text/text_intro.py similarity index 65% rename from doc/users/text_intro.rst rename to tutorials/text/text_intro.py index 93c30ef929c4..01e584b0033f 100644 --- a/doc/users/text_intro.rst +++ b/tutorials/text/text_intro.py @@ -1,13 +1,15 @@ -.. _text-intro: - +""" Text introduction ================= -matplotlib has extensive text support, including support for +Introduction to plotting and working with text in Matplotlib. + +Matplotlib has extensive text support, including support for mathematical expressions, truetype support for raster and vector outputs, newline separated text with arbitrary -rotations, and unicode support. Because it embeds -fonts directly in output documents, e.g., for postscript +rotations, and unicode support. + +Because it embeds fonts directly in output documents, e.g., for postscript or PDF, what you see on the screen is what you get in the hardcopy. `FreeType `_ support produces very nice, antialiased fonts, that look good even at small @@ -22,7 +24,7 @@ And significantly, for those interested in mathematical or scientific figures, matplotlib implements a large number of TeX math symbols and commands, supporting :ref:`mathematical expressions -` anywhere in your figure. +` anywhere in your figure. Basic text commands @@ -57,12 +59,37 @@ :func:`matplotlib.text.Text` instance, which can be configured with a variety of font and other properties. The example below shows all of these commands in action. +""" + +import matplotlib.pyplot as plt + +fig = plt.figure() +fig.suptitle('bold figure suptitle', fontsize=14, fontweight='bold') + +ax = fig.add_subplot(111) +fig.subplots_adjust(top=0.85) +ax.set_title('axes title') + +ax.set_xlabel('xlabel') +ax.set_ylabel('ylabel') + +ax.text(3, 8, 'boxed italics text in data coords', style='italic', + bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10}) + +ax.text(2, 6, r'an equation: $E=mc^2$', fontsize=15) + +ax.text(3, 2, u'unicode: Institut f\374r Festk\366rperphysik') + +ax.text(0.95, 0.01, 'colored text in axes coords', + verticalalignment='bottom', horizontalalignment='right', + transform=ax.transAxes, + color='green', fontsize=15) -.. figure:: ../gallery/pyplots/images/sphx_glr_text_commands_001.png - :target: ../gallery/pyplots/text_commands.html - :align: center - :scale: 50 - Text Commands +ax.plot([2], [1], 'o') +ax.annotate('annotate', xy=(2, 1), xytext=(3, 4), + arrowprops=dict(facecolor='black', shrink=0.05)) +ax.axis([0, 10, 0, 10]) +plt.show() diff --git a/tutorials/text/text_props.py b/tutorials/text/text_props.py new file mode 100644 index 000000000000..9afca3fa7777 --- /dev/null +++ b/tutorials/text/text_props.py @@ -0,0 +1,235 @@ +""" +============================ + Text properties and layout +============================ + +Controlling properties of text and its layout with Matplotlib. + +The :class:`matplotlib.text.Text` instances have a variety of +properties which can be configured via keyword arguments to the text +commands (e.g., :func:`~matplotlib.pyplot.title`, +:func:`~matplotlib.pyplot.xlabel` and :func:`~matplotlib.pyplot.text`). + +========================== ====================================================================================================================== +Property Value Type +========================== ====================================================================================================================== +alpha `float` +backgroundcolor any matplotlib :ref:`color ` +bbox `~matplotlib.patches.Rectangle` prop dict plus key ``'pad'`` which is a pad in points +clip_box a matplotlib.transform.Bbox instance +clip_on [True | False] +clip_path a `~matplotlib.path.Path` instance and a `~matplotlib.transforms.Transform` instance, a `~matplotlib.patches.Patch` +color any matplotlib :ref:`color ` +family [ ``'serif'`` | ``'sans-serif'`` | ``'cursive'`` | ``'fantasy'`` | ``'monospace'`` ] +fontproperties a `~matplotlib.font_manager.FontProperties` instance +horizontalalignment or ha [ ``'center'`` | ``'right'`` | ``'left'`` ] +label any string +linespacing `float` +multialignment [``'left'`` | ``'right'`` | ``'center'`` ] +name or fontname string e.g., [``'Sans'`` | ``'Courier'`` | ``'Helvetica'`` ...] +picker [None|float|boolean|callable] +position (x, y) +rotation [ angle in degrees | ``'vertical'`` | ``'horizontal'`` ] +size or fontsize [ size in points | relative size, e.g., ``'smaller'``, ``'x-large'`` ] +style or fontstyle [ ``'normal'`` | ``'italic'`` | ``'oblique'`` ] +text string or anything printable with '%s' conversion +transform a `~matplotlib.transforms.Transform` instance +variant [ ``'normal'`` | ``'small-caps'`` ] +verticalalignment or va [ ``'center'`` | ``'top'`` | ``'bottom'`` | ``'baseline'`` ] +visible [True | False] +weight or fontweight [ ``'normal'`` | ``'bold'`` | ``'heavy'`` | ``'light'`` | ``'ultrabold'`` | ``'ultralight'``] +x `float` +y `float` +zorder any number +========================== ====================================================================================================================== + + +You can lay out text with the alignment arguments +``horizontalalignment``, ``verticalalignment``, and +``multialignment``. ``horizontalalignment`` controls whether the x +positional argument for the text indicates the left, center or right +side of the text bounding box. ``verticalalignment`` controls whether +the y positional argument for the text indicates the bottom, center or +top side of the text bounding box. ``multialignment``, for newline +separated strings only, controls whether the different lines are left, +center or right justified. Here is an example which uses the +:func:`~matplotlib.pyplot.text` command to show the various alignment +possibilities. The use of ``transform=ax.transAxes`` throughout the +code indicates that the coordinates are given relative to the axes +bounding box, with 0,0 being the lower left of the axes and 1,1 the +upper right. +""" + +import matplotlib.pyplot as plt +import matplotlib.patches as patches + +# build a rectangle in axes coords +left, width = .25, .5 +bottom, height = .25, .5 +right = left + width +top = bottom + height + +fig = plt.figure() +ax = fig.add_axes([0, 0, 1, 1]) + +# axes coordinates are 0,0 is bottom left and 1,1 is upper right +p = patches.Rectangle( + (left, bottom), width, height, + fill=False, transform=ax.transAxes, clip_on=False + ) + +ax.add_patch(p) + +ax.text(left, bottom, 'left top', + horizontalalignment='left', + verticalalignment='top', + transform=ax.transAxes) + +ax.text(left, bottom, 'left bottom', + horizontalalignment='left', + verticalalignment='bottom', + transform=ax.transAxes) + +ax.text(right, top, 'right bottom', + horizontalalignment='right', + verticalalignment='bottom', + transform=ax.transAxes) + +ax.text(right, top, 'right top', + horizontalalignment='right', + verticalalignment='top', + transform=ax.transAxes) + +ax.text(right, bottom, 'center top', + horizontalalignment='center', + verticalalignment='top', + transform=ax.transAxes) + +ax.text(left, 0.5*(bottom+top), 'right center', + horizontalalignment='right', + verticalalignment='center', + rotation='vertical', + transform=ax.transAxes) + +ax.text(left, 0.5*(bottom+top), 'left center', + horizontalalignment='left', + verticalalignment='center', + rotation='vertical', + transform=ax.transAxes) + +ax.text(0.5*(left+right), 0.5*(bottom+top), 'middle', + horizontalalignment='center', + verticalalignment='center', + fontsize=20, color='red', + transform=ax.transAxes) + +ax.text(right, 0.5*(bottom+top), 'centered', + horizontalalignment='center', + verticalalignment='center', + rotation='vertical', + transform=ax.transAxes) + +ax.text(left, top, 'rotated\nwith newlines', + horizontalalignment='center', + verticalalignment='center', + rotation=45, + transform=ax.transAxes) + +ax.set_axis_off() +plt.show() + +############################################################################### +# ============== +# Default Font +# ============== +# +# The base default font is controlled by a set of rcParams: +# +# +---------------------+----------------------------------------------------+ +# | rcParam | usage | +# +=====================+====================================================+ +# | ``'font.family'`` | List of either names of font or ``{'cursive', | +# | | 'fantasy', 'monospace', 'sans', 'sans serif', | +# | | 'sans-serif', 'serif'}``. | +# | | | +# +---------------------+----------------------------------------------------+ +# | ``'font.style'`` | The default style, ex ``'normal'``, | +# | | ``'italic'``. | +# | | | +# +---------------------+----------------------------------------------------+ +# | ``'font.variant'`` | Default variant, ex ``'normal'``, ``'small-caps'`` | +# | | (untested) | +# +---------------------+----------------------------------------------------+ +# | ``'font.stretch'`` | Default stretch, ex ``'normal'``, ``'condensed'`` | +# | | (incomplete) | +# | | | +# +---------------------+----------------------------------------------------+ +# | ``'font.weight'`` | Default weight. Either string or integer | +# | | | +# | | | +# +---------------------+----------------------------------------------------+ +# | ``'font.size'`` | Default font size in points. Relative font sizes | +# | | (``'large'``, ``'x-small'``) are computed against | +# | | this size. | +# +---------------------+----------------------------------------------------+ +# +# The mapping between the family aliases (``{'cursive', 'fantasy', +# 'monospace', 'sans', 'sans serif', 'sans-serif', 'serif'}``) and actual font names +# is controlled by the following rcParams: +# +# +# +------------------------------------------+--------------------------------+ +# | family alias | rcParam with mappings | +# +==========================================+================================+ +# | ``'serif'`` | ``'font.serif'`` | +# +------------------------------------------+--------------------------------+ +# | ``'monospace'`` | ``'font.monospace'`` | +# +------------------------------------------+--------------------------------+ +# | ``'fantasy'`` | ``'font.fantasy'`` | +# +------------------------------------------+--------------------------------+ +# | ``'cursive'`` | ``'font.cursive'`` | +# +------------------------------------------+--------------------------------+ +# | ``{'sans', 'sans serif', 'sans-serif'}`` | ``'font.sans-serif'`` | +# +------------------------------------------+--------------------------------+ +# +# +# which are lists of font names. +# +# Text with non-latin glyphs +# ========================== +# +# As of v2.0 the :ref:`default font ` contains +# glyphs for many western alphabets, but still does not cover all of the +# glyphs that may be required by mpl users. For example, DejaVu has no +# coverage of Chinese, Korean, or Japanese. +# +# +# To set the default font to be one that supports the code points you +# need, prepend the font name to ``'font.family'`` or the desired alias +# lists :: +# +# matplotlib.rcParams['font.sans-serif'] = ['Source Han Sans TW', 'sans-serif'] +# +# or set it in your :file:`.matplotlibrc` file:: +# +# font.sans-serif: Source Han Sans TW, Ariel, sans-serif +# +# To control the font used on per-artist basis use the ``'name'``, +# ``'fontname'`` or ``'fontproperties'`` kwargs documented :ref:`above +# `. +# +# +# On linux, `fc-list `__ can be a +# useful tool to discover the font name; for example :: +# +# $ fc-list :lang=zh family +# Noto to Sans Mono CJK TC,Noto Sans Mono CJK TC Bold +# Noto Sans CJK TC,Noto Sans CJK TC Medium +# Noto Sans CJK TC,Noto Sans CJK TC DemiLight +# Noto Sans CJK KR,Noto Sans CJK KR Black +# Noto Sans CJK TC,Noto Sans CJK TC Black +# Noto Sans Mono CJK TC,Noto Sans Mono CJK TC Regular +# Noto Sans CJK SC,Noto Sans CJK SC Light +# +# lists all of the fonts that support Chinese. +# diff --git a/doc/users/usetex.rst b/tutorials/text/usetex.py similarity index 92% rename from doc/users/usetex.rst rename to tutorials/text/usetex.py index 64c678f92633..f0971580724a 100644 --- a/doc/users/usetex.rst +++ b/tutorials/text/usetex.py @@ -1,9 +1,10 @@ -.. _usetex-tutorial: - +""" ************************* Text rendering With LaTeX ************************* +Rendering text with LaTeX in Matplotlib. + Matplotlib has the option to use LaTeX to manage all text layout. This option is available with the following backends: @@ -14,7 +15,7 @@ The LaTeX option is activated by setting ``text.usetex : True`` in your rc settings. Text handling with matplotlib's LaTeX support is slower than matplotlib's very capable :ref:`mathtext -`, but is more flexible, since different LaTeX +`, but is more flexible, since different LaTeX packages (font packages, math packages, etc.) can be used. The results can be striking, especially when you take care to use the same fonts in your figures as in the main document. @@ -25,7 +26,7 @@ external dependencies must all be located on your :envvar:`PATH`. There are a couple of options to mention, which can be changed using :ref:`rc -settings `. Here is an example matplotlibrc file:: +settings `. Here is an example matplotlibrc file:: font.family : serif font.serif : Times, Palatino, New Century Schoolbook, Bookman, Computer Modern Roman @@ -52,8 +53,8 @@ Here is the standard example, `tex_demo.py`: -.. figure:: ../gallery/pyplots/images/sphx_glr_tex_demo_001.png - :target: ../gallery/pyplots/tex_demo.html +.. figure:: ../../gallery/pyplots/images/sphx_glr_tex_demo_001.png + :target: ../../gallery/pyplots/tex_demo.html :align: center :scale: 50 @@ -78,8 +79,8 @@ It is also possible to use unicode strings with the LaTeX text manager, here is an example taken from `tex_unicode_demo.py`: -.. figure:: ../gallery/pylab_examples/images/sphx_glr_tex_unicode_demo_001.png - :target: ../gallery/pylab_examples/tex_unicode_demo.html +.. figure:: ../../gallery/pylab_examples/images/sphx_glr_tex_unicode_demo_001.png + :target: ../../gallery/pylab_examples/tex_unicode_demo.html :align: center :scale: 50 @@ -164,5 +165,4 @@ .. _PSNFSS: http://www.ctan.org/tex-archive/macros/latex/required/psnfss/psnfss2e.pdf .. _Poppler: https://poppler.freedesktop.org/ .. _Xpdf: http://www.foolabs.com/xpdf - - +"""