Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

A (new) cairo backend for Matplotlib.

License

NotificationsYou must be signed in to change notification settings

matplotlib/mplcairo

Repository files navigation

GitHubPyPIFedora Rawhide

This is a new, essentially complete implementation of acairo backend forMatplotlib. It can be used in combination with a Qt, GTK, Tk, wx, or macOSUI, or non-interactively (i.e., to save figure to various file formats).

Noteworthy points include:

  • Improved accuracy (e.g., with marker positioning, quad meshes, and textkerning; floating point surfaces are supported with cairo≥1.17.2).
  • Optional multithreaded drawing of markers and path collections.
  • Optional support for complex text layout (right-to-left languages, etc.) andOpenType font features (seeexamples/opentype_features.py) and variations(seeexamples/opentype_variations.py) (requires cairo≥1.16.0), and partialsupport for color fonts (e.g., emojis), usingRaqm.Note that Raqmdepends by default on Fribidi, which is licensed under the LGPLv2.1+.
  • Support for embedding URLs in PDF (but not SVG) output (requirescairo≥1.15.4).
  • Support for multi-page output both for PDF and PS (Matplotlib only supportsmulti-page PDF).
  • Support for custom blend modes (seeexamples/operators.py).
  • Improved font embedding in vector formats: fonts are typically subsetted andembedded in their native format (Matplotlib≥3.5 also provides improved fontembedding).

mplcairo requires

  • Python≥3.8,
  • Matplotlib≥2.2,
  • on Linux and macOS, pycairo≥1.16.0[1],
  • on Windows, cairo≥1.13.1[2] (shipped with the wheel).

It is recommended to use cairo≥1.17.4.

Additionally, building mplcairo from source requires

  • pybind11≥3.0[3],
  • pycairo≥1.16.0.

As usual, install using pip:

$ pip install mplcairo# from PyPI$ pip install git+https://github.com/matplotlib/mplcairo# from Github

Note that wheels are not available for macOS<10.13, because the libc++ includedwith these versions is too old and vendoring of libc++ appears to be fragile.

mplcairo can useRaqm (≥0.7.0; ≥0.7.2 is recommended as it provides betteremoji support, especially in the presence of ligatures) for complex text layoutand handling of OpenType font features. Refer to the instructions on thatproject's website for installation on Linux and macOS. On Windows, considerusing Christoph Gohlke'sbuild (the directory containinglibraqm.dll andlibfribidi-0.dll need to be added to theDLL searchpath).

[1]

pycairo 1.16.0 addedget_include().

We do not actually rely on pycairo's Python bindings. Rather, thedependency on pycairo (≥1.16.0) conveniently specifies a dependency oncairo (≥1.13.1) itself, and allows us to load cairo at runtime instead oflinking to it (simplifying the build of self-contained wheels).

On Windows, this strategy is (AFAIK) not possible, so we explicitly linkagainst the cairo DLL.

[2]

cairo 1.13.1 matches the oldest version supported by pycairo 1.16.0.

cairo 1.15.4 added support for PDF metadata and links; the presence of thisfeature is detected at runtime.

cairo 1.16.0 added support for font variations; the presence of this featureis detected at runtime.

cairo 1.17.2 added support for floating point surfaces, usable withmplcairo.set_options(image_format=mplcairo.format_t.RGBA128F); thepresence of this feature is detected at runtime. However, cairo 1.17.2(and only that version) also has a bug that causes (in particular) polargridlines to be incorrectly cropped. This bug was fixed in 2d1a137.

cairo 1.17.4 fixed a rare crash in rasterization (in dfe3aa6).

cairo 1.17.8 fixed a crash when outputting in the cairo-script format (in6a81bf8).

[3]pybind11 3.0 supports native enums.

On Fedora, the package is available aspython-mplcairo.

This section is only relevant if you wish to build mplcairo yourself, orpackage it for redistribution. Otherwise, proceed to theUse section.

In all cases, once the dependencies described below are installed, mplcairocan be built and installed using any of the standard commands (pip wheel--no-deps .,pip install .,pip install -e . andpython setup.pybuild_ext -i being the most relevant ones).

The following additional dependencies are required:

  • a C++ compiler with C++17 support, e.g. GCC≥7.2 or Clang≥5.0.

  • cairo and FreeType headers, and pkg-config information to locate them.

    If using conda, they can be installed using

    conda install -y -c conda-forge pycairo pkg-config

    as pycairo (also a dependency) depends on cairo, which depends on freetype.Note that cairo and pkg-config from theanaconda channel willnot work.

    On Linux, they can also be installed with your distribution's package manager(Arch:cairo, Debian/Ubuntu:libcairo2-dev, Fedora:cairo-devel).

Raqm (≥0.2) headers are also needed, but will be automatically downloaded ifnot found.

conda's compilers (gxx_linux-64 on theanaconda channel)currentlyinteract poorly with installing cairo and pkg-config from conda-forge, so you are on your own to install a recent compiler(e.g., using your distribution's package manager). You may want to set theCC andCXX environment variables to point to your C++ compiler if it isnonstandard[4]. In that case, be careful to set them to e.g.g++-7 andnotgcc-7, otherwise the compilation will succeed but the shared objectwill be mis-linked and fail to load.

The manylinux wheel is built usingtools/build-manylinux-wheel.sh.

[4]distutils usesCC forcompiling C++ sources butCXX forlinking them (don't ask). You may run into additional issues ifCC orCXX has multiple words; e.g., ifCC is set toccache g++, youalso need to setCXX toccache gcc.

Clang≥5.0 can be installed fromconda'sanaconda channel (condainstall -c anaconda clangxx_osx-64), or can also be installed with Homebrew(brew install llvm). Note that Homebrew's llvm formula is keg-only, i.e.it requires manual modifications to the PATH and LDFLAGS (as documented bybrew info llvm).

On macOS<10.14, it is additionally necessary to use clang<8.0 (e.g. withbrewinstall llvm@7) as clang 8.0 appears to believe that code relying on C++17can only be run on macOS≥10.14+.

The macOS wheel is built usingtools/build-macos-wheel.sh, which relies ondelocate-wheel (to vendor a recent version of libc++). Currently, it can onlybe built from a Homebrew-clang wheel, not a conda-clang wheel (due to some pathintricacies...).

The following additional dependencies are required:

  • VS2019 (The exact minimum version is unknown, but it is known that mplcairofails to build on the Github Actionswindows-2016 agent and requires thewindows-2019 agent.)

  • cairo headers and import and dynamic libraries (cairo.lib andcairo.dll)with FreeType support. Note that this excludes, inparticular, most Anaconda and conda-forge builds: they do not includeFreeType support.

    The currently preferred solution is to get the headers e.g. from a Linuxdistribution package, the DLL from a pycairo wheel (e.g. from PyPI), andgenerate the import library oneself usingdumpbin andlib.

    Alternatively, very recent conda-forge builds (≥1.16.0 build 1005) doinclude FreeType support. In order to use them, the include path needs to bemodified as described below. (This is currently intentionally disabled bydefault to avoid confusing errors if the cairo build is too old.)

  • FreeType headers and import and dynamic libraries (freetype.lib andfreetype.dll), which can be retrieved fromhttps://github.com/ubawurinna/freetype-windows-binaries, or alternativelyusing conda:

    conda install -y freetype

The (standard)CL andLINK environment variables (which always getprepended respectively to the invocations of the compiler and the linker)should be set as follows:

set CL=/IC:\path\to\dir\containing\cairo.h /IC:\same\for\ft2build.hset LINK=/LIBPATH:C:\path\to\dir\containing\cairo.lib /LIBPATH:C:\same\for\freetype.lib

In particular, in order to use a conda-forge cairo (as described above),{sys.prefix}\Library\include\cairo needs to be added to the include path.

Moreover, we also need to findcairo.dll andfreetype.dll and copythem next tomplcairo's extension module. As the dynamic libraries aretypically found next to import libraries, we search the/LIBPATH: entriesin theLINK environment variable and copy the firstcairo.dll andfreetype.dll found there.

The scripttools/build-windows-wheel.py automates the retrieval of thecairo (assuming that pycairo is already installed) and FreeType DLLs, and thewheel build.

On Linux and Windows, mplcairo can be used as any normal Matplotlib backend:call e.g.matplotlib.use("module://mplcairo.qt") before importing pyplot,add abackend: module://mplcairo.qt line in yourmatplotlibrc, or settheMPLBACKEND environment variable tomodule://mplcairo.qt. Morespecifically, the following backends are provided:

  • module://mplcairo.base (No GUI, but can output to EPS, PDF, PS, SVG, andSVGZ using cairo's implementation, rather than Matplotlib's),
  • module://mplcairo.gtk (GTK widget, copying data from a cairo imagesurface — GTK3 or GTK4 can be selected by callinggi.require_version("Gtk", "3.0") orgi.require_version("Gtk", "4.0")before importing the backend),
  • module://mplcairo.gtk_native (GTK widget, directly drawn onto as anative surface; does not and cannot support blitting — see above for versionselection),
  • module://mplcairo.qt (Qt widget, copying data from a cairo imagesurface — select the binding to use by importing it before mplcairo, or bysetting theQT_API environment variable),
  • module://mplcairo.tk (Tk widget, copying data from a cairo imagesurface),
  • module://mplcairo.wx (wx widget, copying data from a cairo imagesurface),
  • module://mplcairo.macosx (macOS widget, copying data from a cairo imagesurface).

On macOS, prior to Matplotlib 3.8,it was necessary to explicitly importmplcairo before importing Matplotlib (unless your Matplotlib is built withsystem_freetype = True). A practical option was to import mplcairo, thencall e.g.matplotlib.use("module://mplcairo.macosx").

Jupyter is entirely unsupported (patches would be appreciated). Onepossibility is to set theMPLCAIRO_PATCH_AGG environment variable to anon-empty valuebefore importing Matplotlib; this fully replaces the Aggrenderer by the cairo renderer throughout Matplotlib. However, this approachis inefficient (due to the need of copies and conversions between premultipliedARGB32 and straight RGBA8888 buffers); additionally, it does not work withthe wx and macosx backends due to peculiarities of the corresponding canvasclasses. On the other hand, this is currently the only way in which thewebagg-based backends (e.g., Jupyter's interactive widgets) can use mplcairo.

At import-time, mplcairo will attempt to loadRaqm. The use of that librarycan be controlled and checked using theset_options andget_optionsfunctions.

Theexamples directory contains a few cases where the output of this rendereris arguably more accurate than the one of the default renderer, Agg:

Install (in the virtualenv)pytest>=3.1.0 andpytest-benchmark, thencall (e.g.):

pytest --benchmark-group-by=fullfunc --benchmark-timer=time.process_time

Keep in mind that conda-forge's cairo is (on my setup) ~2× slower than a"native" build of cairo.

Runrun-mpl-test-suite.py (which depends onpytest>=3.2.2) to run theMatplotlib test suite with the Agg backend patched by the mplcairo backend.Note that Matplotlib must be installed with its test data, which is not thecase when it is installed from conda or from most Linux distributions; instead,it should be installed from PyPI or from source.

Nearly all image comparison tests "fail" as the renderers are fundamentallydifferent; currently, the intent is to manually check the diff images. Passing--tolerance=inf marks these tests as "passed" (while still textuallyreporting the image differences) so that one can spot issues not related torendering differences. In practice,--tolerance=50 appears to be enough.

Some other (non-image-comparison) tests are also known to fail (they are listedinISSUES.rst, with the relevant explanations), and automatically skipped.

Runrun-examples.py to run some examples that exercise some more aspects ofmplcairo.

The artist antialiasing property can be set to any of thecairo_antialias_tenum values, orTrue (the default) orFalse (which is synonym toNONE).

Setting antialiasing toTrue usesFAST antialiasing for lines thickerthan 1/3px andBEST for lines thinner than that: for lines thinnerthan 1/3px, the former leads to artefacts such as lines disappearing incertain sections (see e.g.test_cycles.test_property_collision_plot afterforcing the antialiasing toFAST). The threshold of 1/3px was determinedempirically, seeexamples/thin_line_antialiasing.py.

Note that in order to set thelines.antialiased orpatch.antialiasedrcparams to acairo_antialias_t enum value, it is necessary to bypassrcparam validation, using, e.g.

dict.__setitem__(plt.rcParams,"lines.antialiased",antialias_t.FAST)

Thetext.antialiased rcparam can likewise be set to anycairo_antialias_t enum value, orTrue (the default, which maps toSUBPIXELGRAY is not sufficient to benefit fromRaqm's subpixelpositioning; see alsocairo issue #152) orFalse (whichmaps toNONE).

Note that in rare cases, on cairo<1.17.4,FAST antialiasing can trigger a"double free or corruption" bug in cairo (#44). If you hit thisproblem, consider usingBEST orNONE antialiasing (depending on yourquality and speed requirements).

For fast drawing of path with many segments, theagg.path.chunksize rcparamshould be set to e.g. 1000 (seeexamples/time_drawing_per_element.py for thedetermination of this value); this causes longer paths to be split intoindividually rendered sections of 1000 segments each (directly rendering longerpaths appears to have slightly superlinear complexity).

Thepath.simplify_threshold rcparam is used to control the accuracy ofmarker stamping, down to an arbitrarily chosen threshold of 1/16px. If thethreshold is set to a lower value, the exact (slower) marker drawing path willbe used. Marker stamping is also implemented for scatter plots (which can havemultiple colors). Likewise, markers of different sizes get mapped into markersof discretized sizes, with an error bounded by the threshold.

NOTE:pcolor and mplot3d'splot_surface display some artefactswhere the facets join each other. This is because these functions internallyuse aPathCollection; this triggers the approximate stamping, andeven without it (by settingpath.simplify_threshold to zero), cairo'srasterization of the edge between the facets is poor.pcolormesh (whichinternally uses aQuadMesh) should generally be preferred overpcoloranyways.plot_surface could likewise instead represent the surface usingQuadMesh, which is drawn without such artefacts.

In order to use a specific font that Matplotlib may be unable to use, pass afilename directly:

frommatplotlib.font_managerimportFontPropertiesfig.text(.5,.5,"hello, world",fontproperties=FontProperties(fname="/path/to/font.ttf"))

or more simply, with Matplotlib≥3.3:

frompathlibimportPathfig.text(.5,.5,"hello, world",font=Path("/path/to/font.ttf"))

mplcairo still relies on Matplotlib's font cache, so fonts unsupported byMatplotlib remain unavailable by other means.

For TTC fonts (and, more generally, font formats that include multiple fontfaces in a single file), thenth font (n≥0) can be selected by appending#n to the filename (e.g.,"/path/to/font.ttc#1").

OpenType font features can be selected by appending|feature,...to the filename, followed by aHarfBuzz feature string (e.g.,"/path/to/font.otf|frac,onum"); seeexamples/opentype_features.py. Alanguage tag can likewise be set with|language=...; currently, thisalways applies to the whole buffer, but a PR adding support for slicing syntax(similar to font features) would be considered.

OpenType font variations can be selected by appending an additional| tothe filename, followed by aCairo font variation string (e.g.,"/path/to/font.otf||wdth=75"); seeexamples/opentype_variations.py. Thissupport requires Cairo>=1.16. Note that features are parsed first, so if you donot wish to specify any features, you must specify an empty set with two pipes,i.e.,font.otf|variations will treatvariations as features,notvariations.

The syntaxes for selecting TTC subfonts and OpenType font features and languagetags areexperimental and may change, especially if such features areimplemented in Matplotlib itself.

Color fonts (e.g. emojis) are handled.

Matplotlib'sPdfPages class is deeply tied with the builtinbackend_pdf(in fact, it cannot even be used with Matplotlib's own cairo backend).Instead, usemplcairo.multipage.MultiPage for multi-page PDF and PS output.The API is similar:

frommplcairo.multipageimportMultiPagefig1= ...fig2= ...withMultiPage(path_or_stream,metadata=...)asmp:mp.savefig(fig1)mp.savefig(fig2)

See the class' docstring for additional information.

cairo is able to write PDF 1.4 and 1.5 (defaulting to 1.5), PostScript levels 2and 3 (defaulting to 3), and SVG versions 1.1 and 1.2 (defaulting to 1.1).This can be controlled by passing ametadata dict tosavefig with aMaxVersion entry, which must be one of the strings"1.4"/"1.5" (forpdf),"2"/"3" (for ps), or"1.1"/"1.2" (for svg).

Setting theMPLCAIRO_SCRIPT_SURFACE environment variablebefore mplcairois imported tovector orraster allows one to save figures (withsavefig) in the.cairoscript format, which is a "native script thatmatches the cairo drawing model". The value of the variable determines therendering path used (e.g., whether marker stamping is used at all). This maybe helpful for troubleshooting purposes.

Note that cairo-script output is generally broken on cairo≤1.17.8.

draw_markers draws a marker at each control point of the given path, whichis the documented behavior, even though all builtin renderers only draw markersat straight or Bézier segment ends.

Due to missing support from cairo:

  • SVG output does not support global metadata or set URLs or ids on anyelement, as cairo provides no support to do so.
  • PS output does not respect SOURCE_DATE_EPOCH.
  • PS output does not support theCreator metadata key; however it supportstheTitle key.
  • The following rcparams have no effect:
    • pdf.fonttype (font type is selected by cairo internally),
    • pdf.inheritcolor (effectively alwaysFalse),
    • pdf.use14corefonts (effectively alwaysFalse),
    • ps.fonttype (font type is selected by cairo internally),
    • ps.useafm (effectively alwaysFalse),
    • svg.fonttype (effectively always"path", seecairo issue #253),
    • svg.hashsalt,svg.id.

Additionally, thequality,optimize, andprogressive parameters tosavefig, which have been removed in Matplotlib 3.5, are not supported.

  • Cache eviction policy and persistent cache fordraw_path_collection.
  • Use QtOpenGLWidget and the cairo-gl backend.

They are very slow (try runningexamples/mplot3d/wire3d_animation.py) andrender math poorly (trytitle(r"$\sqrt{2}$")).

About

A (new) cairo backend for Matplotlib.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors8


[8]ページ先頭

©2009-2025 Movatter.jp