Giter Club home page Giter Club logo

mplcairo's Introduction

A (new) cairo backend for Matplotlib

local

This is a new, essentially complete implementation of a cairo backend for Matplotlib. It can be used in combination with a Qt, GTK, Tk, wx, or macOS UI, 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 text kerning; 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.) and OpenType font features (see examples/opentype_features.py) and variations (see examples/opentype_variations.py) (requires cairo≥1.16.0), and partial support for color fonts (e.g., emojis), using Raqm. Note that Raqm depends by default on Fribidi, which is licensed under the LGPLv2.1+.
  • Support for embedding URLs in PDF (but not SVG) output (requires cairo≥1.15.4).
  • Support for multi-page output both for PDF and PS (Matplotlib only supports multi-page PDF).
  • Support for custom blend modes (see examples/operators.py).
  • Improved font embedding in vector formats: fonts are typically subsetted and embedded in their native format (Matplotlib≥3.5 also provides improved font embedding).

Installation

mplcairo requires

  • Python≥3.7,
  • Matplotlib≥2.2 (declared as install_requires),
  • on Linux and macOS, pycairo≥1.16.01 (declared as install_requires),
  • on Windows, cairo≥1.13.12 (shipped with the wheel).

It is recommended to use cairo≥1.17.4.

Additionally, building mplcairo from source requires

  • pybind11≥2.6.03 (declared as setup_requires),
  • pycairo≥1.16.0 (declared as setup_requires).

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++ included with these versions is too old and vendoring of libc++ appears to be fragile.

mplcairo can use Raqm (≥0.7.0; ≥0.7.2 is recommended as it provides better emoji support, especially in the presence of ligatures) for complex text layout and handling of OpenType font features. Refer to the instructions on that project's website for installation on Linux and macOS. On Windows, consider using Christoph Gohlke's build (the directory containing libraqm.dll and libfribidi-0.dll need to be added to the DLL search path).

On Fedora, the package is available as python-mplcairo.

Building/packaging

This section is only relevant if you wish to build mplcairo yourself, or package it for redistribution. Otherwise, proceed to the Use section.

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

Unix

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 the anaconda channel will not 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 if not found.

Linux

conda's compilers (gxx_linux-64 on the anaconda channel) currently interact 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 the CC and CXX environment variables to point to your C++ compiler if it is nonstandard4. In that case, be careful to set them to e.g. g++-7 and not gcc-7, otherwise the compilation will succeed but the shared object will be mis-linked and fail to load.

The manylinux wheel is built using tools/build-manylinux-wheel.sh.

macOS

Clang≥5.0 can be installed from conda's anaconda channel (conda install -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 by brew info llvm).

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

The macOS wheel is built using tools/build-macos-wheel.sh, which relies on delocate-wheel (to vendor a recent version of libc++). Currently, it can only be built from a Homebrew-clang wheel, not a conda-clang wheel (due to some path intricacies...).

Windows

The following additional dependencies are required:

  • VS2019 (The exact minimum version is unknown, but it is known that mplcairo fails to build on the Github Actions windows-2016 agent and requires the windows-2019 agent.)
  • cairo headers and import and dynamic libraries (cairo.lib and cairo.dll) with FreeType support. Note that this excludes, in particular, most Anaconda and conda-forge builds: they do not include FreeType support.

    The currently preferred solution is to get the headers e.g. from a Linux distribution package, the DLL from a pycairo wheel (e.g. from PyPI), and generate the import library oneself using dumpbin and lib.

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

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

    conda install -y freetype

The (standard) CL_ and LINK_ environment variables (which always get prepended 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.h
set 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 find cairo.dll and freetype.dll and copy them next to mplcairo's extension module. As the dynamic libraries are typically found next to import libraries, we search the /LIBPATH: entries in the LINK environment variable and copy the first cairo.dll and freetype.dll found there.

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

Use

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 a backend: module://mplcairo.qt line in your matplotlibrc, or set the MPLBACKEND environment variable to module://mplcairo.qt. More specifically, the following backends are provided:

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

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

Jupyter is entirely unsupported (patches would be appreciated). One possibility is to set the MPLCAIRO_PATCH_AGG environment variable to a non-empty value before importing Matplotlib; this fully replaces the Agg renderer by the cairo renderer throughout Matplotlib. However, this approach is inefficient (due to the need of copies and conversions between premultiplied ARGB32 and straight RGBA8888 buffers); additionally, it does not work with the wx and macosx backends due to peculiarities of the corresponding canvas classes. On the other hand, this is currently the only way in which the webagg-based backends (e.g., Jupyter's interactive widgets) can use mplcairo.

At import-time, mplcairo will attempt to load Raqm. The use of that library can be controlled and checked using the set_options and get_options functions.

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

Benchmarks

Install (in the virtualenv) pytest>=3.1.0 and pytest-benchmark, then call (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.

Test suite

Run run-mpl-test-suite.py (which depends on pytest>=3.2.2) to run the Matplotlib test suite with the Agg backend patched by the mplcairo backend. Note that Matplotlib must be installed with its test data, which is not the case 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 fundamentally different; currently, the intent is to manually check the diff images. Passing --tolerance=inf marks these tests as "passed" (while still textually reporting the image differences) so that one can spot issues not related to rendering differences. In practice, --tolerance=50 appears to be enough.

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

Run run-examples.py to run some examples that exercise some more aspects of mplcairo.

Notes

Antialiasing

The artist antialiasing property can be set to any of the cairo_antialias_t enum values, or True (the default) or False (which is synonym to NONE).

Setting antialiasing to True uses FAST antialiasing for lines thicker than 1/3px and BEST for lines thinner than that: for lines thinner than 1/3px, the former leads to artefacts such as lines disappearing in certain sections (see e.g. test_cycles.test_property_collision_plot after forcing the antialiasing to FAST). The threshold of 1/3px was determined empirically, see examples/thin_line_antialiasing.py.

Note that in order to set the lines.antialiased or patch.antialiased rcparams to a cairo_antialias_t enum value, it is necessary to bypass rcparam validation, using, e.g.

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

The text.antialiased rcparam can likewise be set to any cairo_antialias_t enum value, or True (the default, which maps to SUBPIXELGRAY is not sufficient to benefit from Raqm's subpixel positioning; see also cairo issue #152) or False (which maps to NONE).

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 this problem, consider using BEST or NONE antialiasing (depending on your quality and speed requirements).

Fast drawing

For fast drawing of path with many segments, the agg.path.chunksize rcparam should be set to e.g. 1000 (see examples/time_drawing_per_element.py for the determination of this value); this causes longer paths to be split into individually rendered sections of 1000 segments each (directly rendering longer paths appears to have slightly superlinear complexity).

Simplification threshold

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

NOTE: pcolor and mplot3d's plot_surface display some artefacts where the facets join each other. This is because these functions internally use a PathCollection; this triggers the approximate stamping, and even without it (by setting path.simplify_threshold to zero), cairo's rasterization of the edge between the facets is poor. pcolormesh (which internally uses a QuadMesh) should generally be preferred over pcolor anyways. plot_surface could likewise instead represent the surface using QuadMesh, which is drawn without such artefacts.

Font formats and features

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

from matplotlib.font_manager import FontProperties
fig.text(.5, .5, "hello, world",
         fontproperties=FontProperties(fname="/path/to/font.ttf"))

or more simply, with Matplotlib≥3.3:

from pathlib import Path
fig.text(.5, .5, "hello, world", font=Path("/path/to/font.ttf"))

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

For TTC fonts (and, more generally, font formats that include multiple font faces in a single file), the nth 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 a HarfBuzz feature string (e.g., "/path/to/font.otf|frac,onum"); see examples/opentype_features.py. A language tag can likewise be set with |language=...; currently, this always 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 | to the filename, followed by a Cairo font variation string (e.g., "/path/to/font.otf||wdth=75"); see examples/opentype_variations.py. This support requires Cairo>=1.16. Note that features are parsed first, so if you do not wish to specify any features, you must specify an empty set with two pipes, i.e., font.otf|variations will treat variations as features, not variations.

The syntaxes for selecting TTC subfonts and OpenType font features and language tags are experimental and may change, especially if such features are implemented in Matplotlib itself.

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

Multi-page output

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

from mplcairo.multipage import MultiPage

fig1 = ...
fig2 = ...
with MultiPage(path_or_stream, metadata=...) as mp:
    mp.savefig(fig1)
    mp.savefig(fig2)

See the class' docstring for additional information.

Version control for vector formats

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

cairo-script output

Setting the MPLCAIRO_SCRIPT_SURFACE environment variable before mplcairo is imported to vector or raster allows one to save figures (with savefig) in the .cairoscript format, which is a "native script that matches the cairo drawing model". The value of the variable determines the rendering path used (e.g., whether marker stamping is used at all). This may be helpful for troubleshooting purposes.

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

Markers at Bézier control points

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

Known differences

Due to missing support from cairo:

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

Additionally, the quality, optimize, and progressive parameters to savefig, which have been removed in Matplotlib 3.5, are not supported.

Possible optimizations

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

What about the already existing cairo (gtk/qt/wx/tk/...cairo) backends?

They are very slow (try running examples/mplot3d/wire3d_animation.py) and render math poorly (try title(r"$\sqrt{2}$")).


  1. pycairo 1.16.0 added get_include().

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

    On Windows, this strategy is (AFAIK) not possible, so we explicitly link against 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 this feature is detected at runtime.

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

    cairo 1.17.2 added support for floating point surfaces, usable with mplcairo.set_options(float_surface=True); the presence of this feature is detected at runtime. However, cairo 1.17.2 (and only that version) also has a bug that causes (in particular) polar gridlines 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 (in 6a81bf8).

  3. pybind11 2.6.0 is needed to support Python 3.9.

  4. distutils uses CC for compiling C++ sources but CXX for linking them (don't ask). You may run into additional issues if CC or CXX has multiple words; e.g., if CC is set to ccache g++, you also need to set CXX to ccache gcc.

mplcairo's People

Contributors

anntzer avatar azure-pipelines[bot] avatar brienna avatar dnadlinger avatar greglucas avatar qulogic avatar tacaswell avatar tzdyrski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mplcairo's Issues

The sizes of saved vector outputs (PDF, EPS) are too large.

Version Information

>>> import mplcairo
>>> mplcairo.get_versions()
{'python': '3.9.5 (default, Jun  4 2021, 12:28:51) \n[GCC 7.5.0]', 'mplcairo': '0.4', 'matplotlib': '3.5.1', 'cairo': '1.16.0', 'freetype': '2.10.1', 'pybind11': '2.6.2', 'raqm': None, 'hb': None}

Problem Specification

mplcairo Backend

Code:

from pathlib import Path

import numpy as np
import matplotlib
print("matplotlib.__version__:", matplotlib.__version__)
print('Default backend:', matplotlib.get_backend())
matplotlib.use("module://mplcairo.base")
# matplotlib.use("cairo")
print('Backend is now:', matplotlib.get_backend())
import matplotlib.pyplot as plt
matplotlib.rcParams['pdf.fonttype'] = 42
matplotlib.rcParams['ps.fonttype'] = 42


def format_size(num, suffix="B"):
    """Reference: https://stackoverflow.com/a/1094933
    """
    for unit in ["", "K", "M", "G", "T", "P", "E", "Z"]:
        if abs(num) < 1024.0:
            return f"{num:3.1f}{unit}{suffix}"
        num /= 1024.0
    return f"{num:.1f}Y{suffix}"


# Plot and save figures
fig, ax = plt.subplots(figsize=(8,6), dpi=300)
for i in range(5):
    ax.plot(range(100000), np.random.rand(100000), linewidth=2.0)
fig.savefig('./mplcairo_file_size_test.pdf', format='pdf', bbox_inches='tight')
fig.savefig('./mplcairo_file_size_test.eps', format='eps', bbox_inches='tight')
fig.savefig('./mplcairo_file_size_test.png', format='png', bbox_inches='tight')
print("Figures saved!")


# Display the sizes
pathlist = [ Path("./mplcairo_file_size_test.pdf"), Path("./mplcairo_file_size_test.eps"), Path("./mplcairo_file_size_test.png") ]
for path in sorted(pathlist):
    print("{:s}: {:s}".format(path.name, format_size(path.stat().st_size)))

Output:

matplotlib.__version__: 3.5.1
Default backend: module://matplotlib_inline.backend_inline
Backend is now: module://mplcairo.base
Figures saved!
mplcairo_file_size_test.eps: 8.4MB
mplcairo_file_size_test.pdf: 8.4MB
mplcairo_file_size_test.png: 63.2KB

Default Backend

Code is the same as the mplcairo code except that the matplotlib.use line is commented out so that the default backend is used.

Output:

matplotlib.__version__: 3.5.1
Default backend: module://matplotlib_inline.backend_inline
Backend is now: module://matplotlib_inline.backend_inline
Figures saved!
mplcairo_file_size_test.eps: 1.2MB
mplcairo_file_size_test.pdf: 535.4KB
mplcairo_file_size_test.png: 76.8KB

Observation

The vector files (PDF, EPS) produced by mplcairo are much larger than those produced by the default backend (8.4MB v.s. 1.2MB). This issue is worse when there are more lines (Artists) in the figure. The difference in the file size is too large.

Use MultiPages

I am using matplotlib to plot graphs in an Arch Linux container linked here.

I would like to use the MultiPage feature in Cairo but downloading this repo in a container with Arch Linux is complex and I do not want too many dependencies for my container.

I only need the classes for the MultiPages feature in this repo. I am having trouble doing this. GraphicsContextRendererCairo is required to define MultiPages but GraphicsContextRendererCairo needs _mplcairo.GraphicsContextRendererCairo. Where can I find the definition of _mplcairo.GraphicsContextRendererCairo.

Will not compile on OX X 10.14

when doing pip3 install mplcairo on the new version of OS X (Mojave) I get:

    src/_mplcairo.cpp:42:3: error: call to unavailable function 'visit': introduced in macOS 10.14
      std::visit([&](auto const& aa) -> void {
      ^~~~~~~~~~
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/variant:1524:26: note: candidate function [with _Visitor = (lambda at src/_mplcairo.cpp:42:14), _Vs = <const std::__1::variant<_cairo_antialias, bool> &>] has been explicitly made unavailable
    constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {
                             ^

Optimal usage for better rendering speed for multiple (video) frames based on mplcairo?

I am using matplotlib and mplcairo.base for rendering videos. I am using pillow for some post-processing of the individual video frames, so I am (a) triggering figure.canvas.draw() and (b) I am converting the figure to a pillow image by invoking PIL.Image.fromarray(figure.canvas.renderer.buffer_rgba()). I am intentionally creating a new figure per video frame (though this could be simplified in one way or the other). For a complete self-contained example, see below.

On a single core of a somewhat dated 3rd-gen i7, I am getting about 10 frames per second based on this approach. I was wondering whether there is any potential for further optimizations (with respect to the usage of matplotlib and mplcairo.base) that I may have overlooked.

import mplcairo.base # import before matplotlib (?)
import matplotlib
matplotlib.use("module://mplcairo.base", force = True) # use mplcairo.base as non-GUI backend
import matplotlib.pyplot as plt # import pyplot last

from PIL.Image import fromarray

from tqdm import tqdm

FRAMES = 120
DPI = 100
x = list(range(FRAMES))
y = [item ** 2 for item in x]

stream = open('/dev/null', 'wb') # target for images ... something like ffmpeg

for frame_number in tqdm(range(FRAMES)):

    fig = plt.figure(figsize = (1920 / DPI, 1080 / DPI), dpi = DPI)

    ax = fig.subplots()
    ax.plot(x[frame_number], y[frame_number]) # simple test plot

    fig.canvas.draw() # draw figure (appears to be required?)
    image = fromarray(fig.canvas.renderer.buffer_rgba()) # convert image to PIL object

    plt.close(fig) # destroy figure

    # some post-proc on "image" ...

    image.save(stream, 'bmp') # send image to stream
    stream.flush() # flush the stream's buffer
    image.close() # destroy image

stream.close()

Using locl features available in a font

Current documentation and examples show how to control opentype features available in a font, but there are no examples of how to control the opentype language system that is used.

Is specification of language system currently available in mplcairo, and if so, how to specify the language system to be used for text rendering?

Unexpected fallback to Qt5Agg and exception with some zooming conditions

Disclaimer

I am neither sure if there is actually 1 or 2 issues, nor that it is really an issue with mplcairo or something more subtle but definitively part of the vanilla Matplotlib backends 🐑 .

Code snippet

# -*- coding: utf-8 -*-

"""
Filename: example_issue_mplcairo.py
"""

import numpy as np
import matplotlib
matplotlib.use("module://mplcairo.qt")  # my default, but just to be sure
#matplotlib.use("Qt5Agg")  # no error is triggered with this backend
print("#0 " + matplotlib.get_backend())
import matplotlib.pyplot as plt

# Prepare data
# ############

# NB: using "real" data bc I couldn't trigger the issue with artificial ones.

data = np.array([
    [0.9010783810870, 0.01630277666922, 0.9094683896745, 0.01026045742829],
    [0.9570786503693, 0.16706294351760, 0.9450353328361, 0.05505800869503],
    [0.9571383849633, 0.16753128736241, 0.9528604472226, 0.08115013837996],
    [0.9571854383087, 0.16790131216395, 0.9560082084967, 0.09529819473078],
    [0.9572052469505, 0.16805737890754, 0.9571888177871, 0.10130912344386],
    [0.9572556034709, 0.16845490694844, 0.9595591931432, 0.11474075575411],
    [0.9572566034023, 0.16846281207996, 0.9636070458793, 0.14280470855909],
    [0.9572595678960, 0.16848625101237, 0.9636078558762, 0.14281109000281],
    [0.9572636787008, 0.16851875978305, 0.9636083939103, 0.14281532901640],
    ])

raw_x0 = data[:, 0]
raw_y0 = data[:, 1]
raw_x1 = data[:, 2]
raw_y1 = data[:, 3]

vmin = max(raw_x0.min(), raw_x1.min())
vmax = min(raw_x0.max(), raw_x1.max())
xx = np.concatenate((raw_x0[(raw_x0 >= vmin) & (raw_x0 <= vmax)],
                     raw_x1[(raw_x1 >= vmin) & (raw_x1 <= vmax)]))
xx.sort()

y0 = np.interp(xx, raw_x0, raw_y0)
y1 = np.interp(xx, raw_x1, raw_y1)

# Prepare figure
# ##############

# Weirdly, the return value from `matplotlib.get_backend()` changes after
# instantiating the figure.

print("#1 " + matplotlib.get_backend())
fig, ax = plt.subplots(num="example_anntzer", clear=True)
print("#2 " + matplotlib.get_backend())

# Plot
# ####

ax.plot(raw_x0, raw_y0, marker="v", color="tab:red", mfc="white")
ax.plot(raw_x1, raw_y1, marker="^", color="tab:blue", mfc="white")
ax.fill_between(xx, y0, y1, interpolate=True, color="tab:purple", alpha=0.5)

fig.tight_layout()
print("#3 " + matplotlib.get_backend())
fig.show()

# Zooming on the x-values corresponding to the last group of values for x0
# will trigger an error with 'mplcairo', but not with 'Qt5Agg'.

Actual outcome

First, why would matplotlib.get_backend() stop returning 'module://mplcairo.qt'? See

In [1]: run example_issue_mplcairo.py
#0 module://mplcairo.qt
#1 module://mplcairo.qt
#2 Qt5Agg
#3 Qt5Agg

Besides, when zooming like on the following screenshot
zooming_triggers_the_exception
I get an error with the following traceback

In [2]: Traceback (most recent call last):
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/matplotlib/backends/backend_qt5.py", line 519, in _draw_idle
    self.draw()
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/mplcairo/base.py", line 225, in draw
    self.figure.draw(self.get_renderer())
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/matplotlib/figure.py", line 1475, in draw
    renderer, self, artists, self.suppressComposite)
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/matplotlib/image.py", line 141, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_base.py", line 2607, in draw
    mimage._draw_list_compositing_images(renderer, self, artists)
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/matplotlib/image.py", line 141, in _draw_list_compositing_images
    a.draw(renderer)
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/matplotlib/collections.py", line 911, in draw
    Collection.draw(self, renderer)
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "/home/adrien/anaconda3/lib/python3.6/site-packages/matplotlib/collections.py", line 337, in draw
    self._offset_position)
ValueError: invalid value (typically too big) for the size of the input (surface, pattern, etc.)

Expected outcome

In [1]: run example_issue_mplcairo.py
#0 module://mplcairo.qt
#1 module://mplcairo.qt
#2 module://mplcairo.qt
#3 module://mplcairo.qt

and no exception raised when zooming on the plot :/.

Platform

  • Python: 3.6 from conda
  • Matplotlib: 2.2.2 from conda
  • mplcairo: from a nighty build made by @anntzer when I was struggling with installing mplcairo...

Poor on-screen font antialiasing/smoothing in mplcairo

I'm trying to switch to using the mplcairo backend because it does certain things better than the MacOSX backend, especially when colormaps have transparency. However, I've noticed that the font smoothing, at least for plots displayed on the screen, is noticeably poorer. The code below offers a MWE:

import numpy as np
from matplotlib import pyplot as plt

fig = plt.figure()
plt.plot(np.linspace(0,1,10), np.linspace(0,1,10), '-o')
plt.setp(plt.gca().get_xticklabels(), size=14)
plt.setp(plt.gca().get_yticklabels(), size=14)

With the mplcairo backend, the tick labels look jagged and not smooth, as below.
Screenshot 2023-12-28 at 4 32 03 PM
Whereas with the MacOSX backend gives me noticeably smoother fonts.
Screenshot 2023-12-28 at 4 33 00 PM

Everything is identical for the production of the two figures except the backend, which I switch in .matplotlibrc. Am I missing something? Is there a way to get mplcairo to render fonts with proper smoothing?

import mplcairo
mplcairo.get_versions()
{'python': '3.11.6 (main, Oct 12 2023, 21:46:57) [Clang 15.0.0 (clang-1500.0.40.1)]',
 'mplcairo': '0.5.post32+ge771c74',
 'matplotlib': '3.8.0',
 'cairo': '1.17.6 @ /Users/sbasu1/packages/macports/lib/libcairo.2.dylib',
 'freetype': '2.13.2 @ /Users/sbasu1/packages/macports/lib/libfreetype.6.dylib',
 'pybind11': '2.11.1',
 'raqm': None,
 'harfbuzz': None}

Conda package?

I wasn't able to find a conda install package. I'm wondering if you've considered creating a conda build package for easier installs in addition to pip install? I'm generally on conda environments rather than pipenv's, so this would make that easier for me. I can look into it more if you'd like help with this at all too.

Unable to install from pip

Hey,

There's a bug with the bundled cairo version with matplotlib that makes the graph cut off at scaled resolutions. This all seems to work fine on latest version of mplplot on my local machine, so I was thinking of bundling mplcairo with application Graphs for the backend, at least until that issue is fixed.

However, I need to bundle mplplot in my Flatpak. In the end, it tries to install it either through pip from source, or using a wheel as published on PyPi. There's no wheels available for Linux on aarch64 architectures unfortunately, and I don't own any aarch64 devices and cannot build these myself. So I was trying to compile this from source with pip.

Unfortunately, here I am running into issues. Just trying on my direct environment, Python 3.11.3 I'm getting the following output:

⬢[sjoerd@toolbox ~]$ python3 -m pip install mplcairo
Defaulting to user installation because normal site-packages is not writeable
Collecting mplcairo
  Using cached mplcairo-0.5.tar.gz (93 kB)
  Preparing metadata (setup.py) ... done
Requirement already satisfied: matplotlib>=2.2 in ./.local/lib/python3.11/site-packages (from mplcairo) (3.6.2)
Requirement already satisfied: pillow in ./.local/lib/python3.11/site-packages (from mplcairo) (9.3.0)
Requirement already satisfied: pycairo>=1.16.0 in /usr/lib64/python3.11/site-packages (from mplcairo) (1.23.0)
Requirement already satisfied: contourpy>=1.0.1 in ./.local/lib/python3.11/site-packages (from matplotlib>=2.2->mplcairo) (1.0.6)
Requirement already satisfied: cycler>=0.10 in ./.local/lib/python3.11/site-packages (from matplotlib>=2.2->mplcairo) (0.11.0)
Requirement already satisfied: fonttools>=4.22.0 in ./.local/lib/python3.11/site-packages (from matplotlib>=2.2->mplcairo) (4.38.0)
Requirement already satisfied: kiwisolver>=1.0.1 in ./.local/lib/python3.11/site-packages (from matplotlib>=2.2->mplcairo) (1.4.4)
Requirement already satisfied: numpy>=1.19 in ./.local/lib/python3.11/site-packages (from matplotlib>=2.2->mplcairo) (1.23.4)
Requirement already satisfied: packaging>=20.0 in ./.local/lib/python3.11/site-packages (from matplotlib>=2.2->mplcairo) (21.3)
Requirement already satisfied: pyparsing>=2.2.1 in ./.local/lib/python3.11/site-packages (from matplotlib>=2.2->mplcairo) (3.0.9)
Requirement already satisfied: python-dateutil>=2.7 in /usr/lib/python3.11/site-packages (from matplotlib>=2.2->mplcairo) (2.8.2)
Requirement already satisfied: six>=1.5 in /usr/lib/python3.11/site-packages (from python-dateutil>=2.7->matplotlib>=2.2->mplcairo) (1.16.0)
Building wheels for collected packages: mplcairo
  Building wheel for mplcairo (setup.py) ... error
  error: subprocess-exited-with-error
  
  × python setup.py bdist_wheel did not run successfully.
  │ exit code: 1
  ╰─> [71 lines of output]
      /var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/installer.py:27: SetuptoolsDeprecationWarning: setuptools.installer is deprecated. Requirements should be satisfied by a PEP 517 installer.
        warnings.warn(
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build/lib.linux-x86_64-cpython-311
      creating build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/wx.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/tk.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/qt.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/multipage.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/macosx.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/gtk_native.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/gtk.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/base.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/_version.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/_util.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/_backports.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      copying lib/mplcairo/__init__.py -> build/lib.linux-x86_64-cpython-311/mplcairo
      running build_ext
      Traceback (most recent call last):
        File "<string>", line 2, in <module>
        File "<pip-setuptools-caller>", line 34, in <module>
        File "/tmp/pip-install-1xf00giz/mplcairo_b82e7a7e4c35426c80a6092b0e7f6261/setup.py", line 189, in <module>
          setup(
        File "/tmp/pip-install-1xf00giz/mplcairo_b82e7a7e4c35426c80a6092b0e7f6261/setupext.py", line 54, in __new__
          setuptools.setup(**kwargs)
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/__init__.py", line 87, in setup
          return distutils.core.setup(**attrs)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/_distutils/core.py", line 185, in setup
          return run_commands(dist)
                 ^^^^^^^^^^^^^^^^^^
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/_distutils/core.py", line 201, in run_commands
          dist.run_commands()
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/_distutils/dist.py", line 968, in run_commands
          self.run_command(cmd)
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/dist.py", line 1217, in run_command
          super().run_command(command)
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/_distutils/dist.py", line 987, in run_command
          cmd_obj.run()
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/wheel/bdist_wheel.py", line 325, in run
          self.run_command("build")
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/_distutils/cmd.py", line 319, in run_command
          self.distribution.run_command(command)
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/dist.py", line 1217, in run_command
          super().run_command(command)
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/_distutils/dist.py", line 987, in run_command
          cmd_obj.run()
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/_distutils/command/build.py", line 132, in run
          self.run_command(cmd_name)
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/_distutils/cmd.py", line 319, in run_command
          self.distribution.run_command(command)
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/dist.py", line 1217, in run_command
          super().run_command(command)
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/_distutils/dist.py", line 986, in run_command
          cmd_obj.ensure_finalized()
        File "/var/home/sjoerd/.local/lib/python3.11/site-packages/setuptools/_distutils/cmd.py", line 109, in ensure_finalized
          self.finalize_options()
        File "/tmp/pip-install-1xf00giz/mplcairo_b82e7a7e4c35426c80a6092b0e7f6261/setup.py", line 123, in finalize_options
          get_pkgconfig(f"--atleast-version={MIN_CAIRO_VERSION}", "cairo")
        File "/tmp/pip-install-1xf00giz/mplcairo_b82e7a7e4c35426c80a6092b0e7f6261/setup.py", line 57, in get_pkgconfig
          return shlex.split(subprocess.check_output(["pkg-config", info, lib],
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib64/python3.11/subprocess.py", line 466, in check_output
          return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/usr/lib64/python3.11/subprocess.py", line 571, in run
          raise CalledProcessError(retcode, process.args,
      subprocess.CalledProcessError: Command '['pkg-config', '--atleast-version=1.11.4', 'cairo']' returned non-zero exit status 1.
      [end of output]
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for mplcairo
  Running setup.py clean for mplcairo
Failed to build mplcairo
ERROR: Could not build wheels for mplcairo, which is required to install pyproject.toml-based projects
⬢[sjoerd@toolbox ~]$ 

In my Flatpak environment (on which Graphs will be compiled), I'm getting similar issues:

========================================================================
Building module python3-mplcairo in /var/home/sjoerd/.var/app/org.gnome.Builder/cache/gnome-builder/flatpak-builder/build/python3-mplcairo-28
========================================================================
Running: pip3 install --verbose --exists-action=i --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST} "mplcairo" --no-build-isolation
Using pip 23.1 from /usr/lib/python3.10/site-packages/pip (python 3.10)
Looking in links: file:///run/build/python3-mplcairo
Processing ./mplcairo-0.5.tar.gz
  Running command python setup.py egg_info
  /usr/lib/python3.10/site-packages/setuptools/__init__.py:85: _DeprecatedInstaller: setuptools.installer and fetch_build_eggs are deprecated. Requirements should be satisfied by a PEP 517 installer. If you are using pip, you can try `pip install --use-pep517`.
    dist.fetch_build_eggs(dist.setup_requires)
  running egg_info
  creating /tmp/pip-pip-egg-info-p0umywf3/mplcairo.egg-info
  writing /tmp/pip-pip-egg-info-p0umywf3/mplcairo.egg-info/PKG-INFO
  writing dependency_links to /tmp/pip-pip-egg-info-p0umywf3/mplcairo.egg-info/dependency_links.txt
  writing requirements to /tmp/pip-pip-egg-info-p0umywf3/mplcairo.egg-info/requires.txt
  writing top-level names to /tmp/pip-pip-egg-info-p0umywf3/mplcairo.egg-info/top_level.txt
  writing manifest file '/tmp/pip-pip-egg-info-p0umywf3/mplcairo.egg-info/SOURCES.txt'
  listing git files failed - pretending there aren't any
  reading manifest file '/tmp/pip-pip-egg-info-p0umywf3/mplcairo.egg-info/SOURCES.txt'
  adding license file 'LICENSE.txt'
  writing manifest file '/tmp/pip-pip-egg-info-p0umywf3/mplcairo.egg-info/SOURCES.txt'
  Preparing metadata (setup.py) ... done
Requirement already satisfied: matplotlib>=2.2 in /app/lib/python3.10/site-packages (from mplcairo) (3.7.1)
Requirement already satisfied: pillow in /app/lib/python3.10/site-packages (from mplcairo) (9.5.0)
Requirement already satisfied: pycairo>=1.16.0 in /usr/lib/python3.10/site-packages (from mplcairo) (1.23.0)
Requirement already satisfied: contourpy>=1.0.1 in /app/lib/python3.10/site-packages (from matplotlib>=2.2->mplcairo) (1.0.7)
Requirement already satisfied: cycler>=0.10 in /app/lib/python3.10/site-packages (from matplotlib>=2.2->mplcairo) (0.11.0)
Requirement already satisfied: fonttools>=4.22.0 in /app/lib/python3.10/site-packages (from matplotlib>=2.2->mplcairo) (4.39.3)
Requirement already satisfied: kiwisolver>=1.0.1 in /app/lib/python3.10/site-packages (from matplotlib>=2.2->mplcairo) (1.4.4)
Requirement already satisfied: numpy>=1.20 in /app/lib/python3.10/site-packages (from matplotlib>=2.2->mplcairo) (1.24.2)
Requirement already satisfied: packaging>=20.0 in /app/lib/python3.10/site-packages (from matplotlib>=2.2->mplcairo) (23.1)
Requirement already satisfied: pyparsing>=2.3.1 in /app/lib/python3.10/site-packages (from matplotlib>=2.2->mplcairo) (3.0.9)
Requirement already satisfied: python-dateutil>=2.7 in /app/lib/python3.10/site-packages (from matplotlib>=2.2->mplcairo) (2.8.2)
Requirement already satisfied: six>=1.5 in /usr/lib/python3.10/site-packages (from python-dateutil>=2.7->matplotlib>=2.2->mplcairo) (1.16.0)
Building wheels for collected packages: mplcairo
  Running command python setup.py bdist_wheel
  /usr/lib/python3.10/site-packages/setuptools/__init__.py:85: _DeprecatedInstaller: setuptools.installer and fetch_build_eggs are deprecated. Requirements should be satisfied by a PEP 517 installer. If you are using pip, you can try `pip install --use-pep517`.
    dist.fetch_build_eggs(dist.setup_requires)
  running bdist_wheel
  running build
  running build_py
  creating build
  creating build/lib.linux-x86_64-cpython-310
  creating build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/wx.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/tk.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/qt.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/multipage.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/macosx.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/gtk_native.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/gtk.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/base.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/_version.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/_util.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/_backports.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  copying lib/mplcairo/__init__.py -> build/lib.linux-x86_64-cpython-310/mplcairo
  running build_ext
  error: <urlopen error [Errno -3] Temporary failure in name resolution>
  error: subprocess-exited-with-error
  
  × python setup.py bdist_wheel did not run successfully.
  │ exit code: 1
  ╰─> See above for output.
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  full command: /usr/bin/python3 -u -c '
  exec(compile('"'"''"'"''"'"'
  # This is <pip-setuptools-caller> -- a caller that pip uses to run setup.py
  #
  # - It imports setuptools before invoking setup.py, to enable projects that directly
  #   import from `distutils.core` to work with newer packaging standards.
  # - It provides a clear error message when setuptools is not installed.
  # - It sets `sys.argv[0]` to the underlying `setup.py`, when invoking `setup.py` so
  #   setuptools doesn'"'"'t think the script is `-c`. This avoids the following warning:
  #     manifest_maker: standard file '"'"'-c'"'"' not found".
  # - It generates a shim setup.py, for handling setup.cfg-only projects.
  import os, sys, tokenize
  
  try:
      import setuptools
  except ImportError as error:
      print(
          "ERROR: Can not execute `setup.py` since setuptools is not available in "
          "the build environment.",
          file=sys.stderr,
      )
      sys.exit(1)
  
  __file__ = %r
  sys.argv[0] = __file__
  
  if os.path.exists(__file__):
      filename = __file__
      with tokenize.open(__file__) as f:
          setup_py_code = f.read()
  else:
      filename = "<auto-generated setuptools caller>"
      setup_py_code = "from setuptools import setup; setup()"
  
  exec(compile(setup_py_code, filename, "exec"))
  '"'"''"'"''"'"' % ('"'"'/tmp/pip-install-bd6was80/mplcairo_524734b2e1c44ceca2a5540ab16a5795/setup.py'"'"',), "<pip-setuptools-caller>", "exec"))' bdist_wheel -d /tmp/pip-wheel-_n6i0o8k
  cwd: /tmp/pip-install-bd6was80/mplcairo_524734b2e1c44ceca2a5540ab16a5795/
  Building wheel for mplcairo (setup.py) ... error
  ERROR: Failed building wheel for mplcairo
  Running setup.py clean for mplcairo
  Running command python setup.py clean
  /usr/lib/python3.10/site-packages/setuptools/__init__.py:85: _DeprecatedInstaller: setuptools.installer and fetch_build_eggs are deprecated. Requirements should be satisfied by a PEP 517 installer. If you are using pip, you can try `pip install --use-pep517`.
    dist.fetch_build_eggs(dist.setup_requires)
  running clean
  removing 'build/lib.linux-x86_64-cpython-310' (and everything under it)
  'build/bdist.linux-x86_64' does not exist -- can't clean it
  'build/scripts-3.10' does not exist -- can't clean it
Failed to build mplcairo
ERROR: Could not build wheels for mplcairo, which is required to install pyproject.toml-based projects


I tried bundling all dependencies seperately into my Flatpak, but that doesn't change anything. It works fine with the wheel, but because we ship Graphs for both x86 and aarch64 architectures, this is not an option right now. The flatpak environment runs on Python 3.10.6. Which should be compatibile with mplcairo.

Do you have any ideas why the pip install seems to be broken?

Edit: Meant the aarch64 architecture that's an issue for me with the wheels. Got it confused with amd64 🤦

Demonstrate purpose of this repository with images

Hello,

I just found your repository and maybe it useful for my problem. This question on stackoverflow lead me here.

Now I don't know what Cairo is supposed to do. I just found the wikipedia page for Cairo but I don't see how this repository interacts with matplotlib. Moreover I don't have the time to pip install your repo and to run the examples.

Can you demonstrate the capabilities of your repository by adding (linking) some images in the markdown.

Thank you

Jupyter Assertion Error / AttributeError: can't set attribute 'renderer'

I am following Brienna's Gist to plot emojis in matplotlib, which has the following code:

# Set the backend to use mplcairo 
import matplotlib, mplcairo
print('Default backend: ' + matplotlib.get_backend()) 
matplotlib.use("module://mplcairo.macosx")
print('Backend is now ' + matplotlib.get_backend())

# IMPORTANT: Import these libraries only AFTER setting the backend
import matplotlib.pyplot as plt, numpy as np
from matplotlib.font_manager import FontProperties

# Load Apple Color Emoji font 
prop = FontProperties(fname='/System/Library/Fonts/Apple Color Emoji.ttc')

# Set up plot
freqs = [301, 96, 53, 81, 42]
labels = ['😊', '😱', '😂', '😄', '😛']
plt.figure(figsize=(12,8))
p1 = plt.bar(np.arange(len(labels)), freqs, 0.8, color="lightblue")
plt.ylim(0, plt.ylim()[1]+30)

# Make labels
for rect1, label in zip(p1, labels):
    height = rect1.get_height()
    plt.annotate(
        label,
        (rect1.get_x() + rect1.get_width()/2, height+5),
        ha="center",
        va="bottom",
        fontsize=30,
        fontproperties=prop
    )

plt.show()

When running this in jupyter notebook, i get the following error:
python[13573:53170] *** Assertion failure in +[NSEvent otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:], NSEvent.m:647

When running this in a python script I get:

Default backend: MacOSX
Backend is now module://mplcairo.macosx
Traceback (most recent call last):
  File "/opt/homebrew/Caskroom/miniconda/base/envs/proj/lib/python3.10/site-packages/matplotlib/backend_bases.py", line 1226, in _on_timer
    ret = func(*args, **kwargs)
  File "/opt/homebrew/Caskroom/miniconda/base/envs/proj/lib/python3.10/site-packages/matplotlib/backends/backend_macosx.py", line 68, in callback_func
    callback()
  File "/opt/homebrew/Caskroom/miniconda/base/envs/proj/lib/python3.10/site-packages/matplotlib/backends/backend_macosx.py", line 88, in _draw_idle
    self.draw()
  File "/opt/homebrew/Caskroom/miniconda/base/envs/proj/lib/python3.10/site-packages/mplcairo/base.py", line 233, in draw
    super().draw()
  File "/opt/homebrew/Caskroom/miniconda/base/envs/proj/lib/python3.10/site-packages/matplotlib/backends/backend_macosx.py", line 50, in draw
    super().draw()
  File "/opt/homebrew/Caskroom/miniconda/base/envs/proj/lib/python3.10/site-packages/matplotlib/backends/backend_agg.py", line 394, in draw
    self.renderer = self.get_renderer()
AttributeError: can't set attribute 'renderer'

I am on a Mac (M2) and mplcairo.get_versions() gives:
{
'python': '3.10.8 (main, Nov 24 2022, 08:08:27) [Clang 14.0.6 ]',
'mplcairo': '0.5',
'matplotlib': '3.7.2',
'cairo': '1.16.0',
'freetype': '2.12.1',
'pybind11': '2.11.1',
'raqm': None,
'hb': None
}

y-axis title rotated

{'python': '3.10.2 (main, Jan 17 2022, 00:00:00) [GCC 11.2.1 20211203 (Red Hat 11.2.1-7)]',
'mplcairo': '0.4',
'matplotlib': '3.5.1',
'cairo': '1.17.4',
'freetype': '2.11.0',
'pybind11': '2.8.1',
'raqm': '0.7.2',
'hb': '2.9.1'}

Very strange issue. Ran a script I've been using for years, and now the y axis label comes out rotated.
I am using Multipage

from mplcairo.multipage import MultiPage

When multipage is not used (the script has option to plot to screen instead) the issue does not appear.

It's not feasible to attach the script and data.

Attached is the pdf output showing the sideways y-axis label, which was produced by:
ax.set_ylabel('bler')
results.2022-02-08.pdf

Jupyter inline plot only appears on second try

Hi. Just found your package and very excited to try additive blending :)

Before that, I wanted to get mplcairo working with my working environment -- Jupyter lab with %matplotlib widget (issue here) or at least %matplotlib inline).

I was able to get the latter to work -- sort of. The following cell needs to be run twice before the results appear.

After first run:

image

After second run:

image

Do you know why this is happening? Any help appreciated!

Result of mplcairo.get_versions()

{'python': '3.6.7 | packaged by conda-forge | (default, Feb 28 2019, 09:07:38) \n[GCC 7.3.0]',
 'mplcairo': '0.3',
 'matplotlib': '3.1.1',
 'cairo': '1.14.12',
 'freetype': '2.10.4',
 'pybind11': '2.5.0',
 'raqm': None}

Wheels for aarch64

Related to issue #46, but since it's a seperate issue I thought I'd file it separately. There's wheels available for x86 on all three major operating systems, and amd64 for Windows.

Is it possible to ship aarch64 wheels as well? Or is this just a lack of a development environment in this architecture that these are not shipped (which is perfectly understandable of course).

asymmetric diamonds

Thanks for developing this new backend!

I'm seeing asymmetric diamonds when using the mplcairo backend.

Here is an example script to reproduce

import matplotlib as mpl
import matplotlib.pyplot as plt

mpl.use('module://mplcairo.base')

fig, ax = plt.subplots()

x = [3, 4, 5]
y = x

ax.plot(
    x, y,
    marker='d',
    color='#fef0d9',
    markersize=10,
    markeredgecolor='#b30000',
)

fig.savefig('test-mplcairo.png')

The output looks like the following. Note the middle diamond is asymmetric

test-mplcairo

This can be compared to the version created using the Cairo backend

import matplotlib as mpl
import matplotlib.pyplot as plt

mpl.use('Cairo')

fig, ax = plt.subplots()

x = [3, 4, 5]
y = x
ax.plot(
    x, y,
    marker='d',
    color='#fef0d9',
    markersize=10,
    markeredgecolor='#b30000',
)

fig.savefig('test-cairo.png')

which looks fine

test-cairo

Here are versions

>>> mplcairo.get_versions()
{'python': '3.7.6 | packaged by conda-forge | (default, Mar 23 2020, 23:03:20) \n[GCC 7.3.0]', 'mplcairo': '0.3', 'matplotlib': '3.2.2', 'cairo': '1.16.0', 'freetype': '2.10.2', 'pybind11': '2.5.0', 'raqm': None}

Pytest hooks not doing anything?

My Fedora builds are failing because of test_lazy_auto_backend_selection. However, even with c0bbfcf patched in, that test still runs.

I tried patching pytest_collection_modifyitems to always apply debugskip, yet all tests seemed to be running. I then tried adding a raise at the beginning of the function, and it never failed.

So I'm beginning to wonder if the pytest hooks are being used at all? This is with pytest 7.1.2 if perhaps something changed there to break it.

Installing from PyPI seems to not work

Installing using pip and git does work fine however... See the output below.

kai@kai-thinkpad ~/u/thesis-kai-mast (master) [1]> pip3 install mplcairo
Collecting mplcairo
  Using cached mplcairo-0.2.tar.gz (113 kB)
    ERROR: Command errored out with exit status 1:
     command: /usr/bin/python3 -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-ievy3i1q/mplcairo/setup.py'"'"'; __file__='"'"'/tmp/pip-install-ievy3i1q/mplcairo/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /tmp/pip-install-ievy3i1q/mplcairo/pip-egg-info
         cwd: /tmp/pip-install-ievy3i1q/mplcairo/
    Complete output (23 lines):
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-install-ievy3i1q/mplcairo/setup.py", line 241, in <module>
        setup(
      File "/tmp/pip-install-ievy3i1q/mplcairo/setupext.py", line 55, in __new__
        setuptools.setup(**kwargs)
      File "/usr/lib/python3/dist-packages/setuptools/__init__.py", line 143, in setup
        _install_setup_requires(attrs)
      File "/usr/lib/python3/dist-packages/setuptools/__init__.py", line 138, in _install_setup_requires
        dist.fetch_build_eggs(dist.setup_requires)
      File "/usr/lib/python3/dist-packages/setuptools/dist.py", line 718, in fetch_build_eggs
        resolved_dists = pkg_resources.working_set.resolve(
      File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 781, in resolve
        dist = best[req.key] = env.best_match(
      File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 1066, in best_match
        return self.obtain(req, installer)
      File "/usr/lib/python3/dist-packages/pkg_resources/__init__.py", line 1078, in obtain
        return installer(requirement)
      File "/usr/lib/python3/dist-packages/setuptools/dist.py", line 777, in fetch_build_egg
        return fetch_build_egg(self, req)
      File "/usr/lib/python3/dist-packages/setuptools/installer.py", line 83, in fetch_build_egg
        raise DistutilsError('the `allow-hosts` option is not supported '
    distutils.errors.DistutilsError: the `allow-hosts` option is not supported when using pip to install requirements.
    ----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.

kai@kai-thinkpad ~/u/thesis-kai-mast (master) [1]> pip3 install git+https://github.com/matplotlib/mplcairo
Collecting git+https://github.com/matplotlib/mplcairo
  Cloning https://github.com/matplotlib/mplcairo to /tmp/pip-req-build-sq8psipm
  Running command git clone -q https://github.com/matplotlib/mplcairo /tmp/pip-req-build-sq8psipm
Requirement already satisfied: matplotlib>=2.2 in /usr/lib/python3/dist-packages (from mplcairo==0.2.post47+gdb53d25) (3.1.2)
Requirement already satisfied: pillow in /usr/lib/python3/dist-packages (from mplcairo==0.2.post47+gdb53d25) (7.0.0)
Requirement already satisfied: pycairo>=1.16.0 in /usr/lib/python3/dist-packages (from mplcairo==0.2.post47+gdb53d25) (1.16.2)
Building wheels for collected packages: mplcairo
  Building wheel for mplcairo (setup.py) ... done
  Created wheel for mplcairo: filename=mplcairo-0.2.post47+gdb53d25-cp38-cp38-linux_x86_64.whl size=3721364 sha256=14f5c6b1c9172e897753f9c88210e5b653085637197e7a7426b92c70fd131451
  Stored in directory: /tmp/pip-ephem-wheel-cache-18hnup9o/wheels/7a/bc/b0/e2e879bde6d9d500436db343e9164de25f77ae7b2ca94d4998
Successfully built mplcairo
Installing collected packages: mplcairo
Successfully installed mplcairo-0.2.post47+gdb53d25

Python 3.11 wheels

A short feature request for Python 3.11 wheels to be built/uploaded 😃

mplcairo-0.1

I noticed a few issues with mplcairo-0.1:

  1. the Windows wheel is missing freetype.dll.

  2. the file mplcairo.pth seems wrong, containing literal "\n" instead of line breaks.

  3. on Windows, I get a segfault when closing the Python interpreter window after executing import mplcairo. I am unable to get a stacktrace.

  4. the documentation claims that the cairo binaries at https://www.lfd.uci.edu/~gohlke/pythonlibs/ are not built with freetype support, however I am sure they are.

Set OpenType features for default plot font

I've just tried out the new OpenType feature support, appears to work nicely on

{'python': '3.7.6 (default, Dec 30 2019, 19:38:28) \n[Clang 11.0.0 (clang-1100.0.33.16)]', 'mplcairo': '0.2.post33+g4b14de1.d20200227', 'matplotlib': '3.1.1', 'cairo': '1.16.0', 'freetype': '2.10.1', 'pybind11': '2.3.0', 'raqm': '0.7.0'}

However, since the syntax isn't integrated with font_manager (which of course would need matplotlib support), it seems like it would be extremely tedious to set properties for default fonts (axes/…) this way – is there a good solution for this?

Circular import error

Hello,

I am attempting to use mplcairo, but I am getting a circular import error.

My code looks like this:

import matplotlib.pyplot as plt
import matplotlib
import mplcairo

# import matplotlib
print('Default backend: ' + matplotlib.get_backend()) 
matplotlib.use("module://mplcairo.macosx")
print('Backend is now ' + matplotlib.get_backend())

And the error I'm getting is this:

Traceback (most recent call last):
  File "/my/file/path", line 14, in <module>
    import mplcairo
  File "/opt/homebrew/lib/python3.11/site-packages/mplcairo/__init__.py", line 27, in <module>
    from . import _mplcairo
ImportError: cannot import name '_mplcairo' from partially initialized module 'mplcairo' (most likely due to a circular import) (/opt/homebrew/lib/python3.11/site-packages/mplcairo/__init__.py)

At first, I was getting this error when I tried running with a normal pip3 install mplcairo so I followed the steps in this link to do a manual build and install of the wheel. The wheel that I built was mplcairo-0.5.post33+g68b4558-cp39-cp39-macosx_11_0_arm64.whl , which gave me an unsupported platform error, but I renamed it to mplcairo-0.5.post33+g68b4558-py39-none-any.whl to see if it would run then (I have an M1 Mac on 14.1.1). The build seemed successful but I am yet again getting the circular import error.

Let me know how I'd be able to fix this and run mplcairo. Thanks!

1st try pdf multipage fail

1st try, converted my code using PdfPages to MultiPage, but got this:

  File "./plot_results_vs_esno2.py", line 317, in <module>
    pdf.savefig (fig)
  File "/home/nbecker/.local/lib/python3.6/site-packages/mplcairo/multipage.py", line 41, in savefig
    self._renderer._set_size(*figure.canvas.get_width_height(),
AttributeError: 'MultiPage' object has no attribute '_renderer'

It's not at all a minimal test case I can upload, but does anyone know what might be the problem?

pkgconfig version checks are broken

has_pkgconfig_raqm is set by the result of get_pkgconfig, but the latter returns the output of pkg-config --atleast-version. This does not print anything at all; the availability of raqm should be determined by the exit code of the pkg-config process.

The other calls with --atleast-version are similarly broken.

blitting support?

$ ipython
Python 3.10.8 (main, Oct 13 2022, 21:13:48) [GCC 12.2.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.5.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import gi

In [2]: gi.require_version("Gtk", "4.0")

In [3]: import matplotlib

In [4]: matplotlib.use("module://mplcairo.gtk")

In [5]: from pylab import *

In [6]: print(FigureCanvasBase.supports_blit)
False

Is it correct that mplcairo.gtk with GTK4 reports that it can't do blitting?

canvas.print_rgba() to_unmultiplied_rgba8888() is extremely slow

assert isinstance(canvas, FigureCanvasCairo):

w = self.cfg.width
h = self.cfg.height
assert (w, h) == canvas.get_width_height()
buffer_rgb = BytesIO()
canvas.print_rgba(buffer_rgb)

old name = mplcairo._util.to_unmultiplied_rgba8888() (renamed in 30db91f) is singlehandedly slowing my 1280x720 render to 11fps. (9.95 sec out of 11 according to CProfile).

I don't even use the alpha channel (fully opaque).


poetry install
  - Installing pycairo (1.18.0)
  - Installing mplcairo (0.1)
import mplcairo
mplcairo.get_versions()
Traceback (most recent call last):
  File "<input>", line 1, in <module>
AttributeError: module 'mplcairo' has no attribute 'get_versions'

Same I pip install git+https://github.com/anntzer/mplcairo from Git master.

Ubuntu 18.04

Package: libcairo2
Version: 1.15.10-2

Package: libcairo2-dev
Version: 1.15.10-2


mplcairo slow.zip

ValueError: Invalid bbox

I have error message when try to run my app with mplcairo from git master.

Traceback (most recent call last):                                                                                                            
  File "/home/ildar/slivoglot-2/thirdparty/matplotlib/lib/matplotlib/cbook/__init__.py", line 216, in process                                 
    func(*args, **kwargs)                                                                                                                     
  File "/home/ildar/slivoglot-2/thirdparty/matplotlib/lib/matplotlib/widgets.py", line 1401, in clear                                         
    self.canvas.copy_from_bbox(self.canvas.figure.bbox))                                                                                      
  File "/opt/slivoglot-2.dev/lib/python3.6/site-packages/mplcairo/base.py", line 237, in copy_from_bbox                                       
    return self.get_renderer(_draw_if_new=True).copy_from_bbox(bbox)                                                                          
ValueError: Invalid bbox  

ipdb> args                                                                                                                                    
self = <gtk.FigureCanvasGTKCairo object at 0xee924af4 (mplcairo+gtk+FigureCanvasGTKCairo at 0x8f7da48)>                                       
bbox = <matplotlib.transforms.TransformedBbox object at 0xee9255cc> 

ipdb> bbox.corners()
array([[  0.,   0.],
       [  0., 627.],
       [972.,   0.],
       [972., 627.]])

Sorry, but I have no small example.

Devanagari script rendering incorrectly

Hi, I've been trying to use mplcairo so I can produce text in Devanagari script. This is due to the normal matplotlib backend not rendering some combined letters correctly. I've tried using both mplcairo.macosx and mplcairo.qt but in both cases the text renders the same as the default matplotlib renderer. This is likely an issue on my side rather than a bug in the code but I'm at my wit's end trying to solve this

{'python': '3.10.13 (main, Sep 11 2023, 08:39:02) [Clang 14.0.6 ]', 'mplcairo': '0.5', 'matplotlib': '3.8.2', 'cairo': '1.16.0', 'freetype': '2.12.1', 'pybind11': '2.10.0', 'raqm': None, 'hb': None}

Example code
`import mplcairo
import matplotlib
matplotlib.use("module://mplcairo.qt")
import matplotlib.pyplot as plt

plt.rcParams['font.family']='Devanagari MT'
plt.figure()
plt.plot([0,1],[0,1])

plt.title(r"विद्युतचुंबकीय विकिरण")
plt.savefig("test.pdf")`

Running on M2 Macbook Air

Output
test.pdf

Macosx interactive zoom rectangle not updating

When using the zoom rectangle with the macosx backend, the area highlighted with zoom is not updated immediately. First, it renders itself into the zoomed rectangle, rather than updating the axes. If I then go and adjust the figure window size, that triggers an update of the zoomed region to the full axes. Additionally, in the GUI window it will be showing incorrectly, but if I save the image, the proper image with the zoom is saved. This is presumably because some update/resize_event is triggered on save.

The QT GUI window works as expected. I looked at the code in the QT backend and there is a repaint on every update it looks like. I'm wondering if that logic needs to be propagated into the macosx backend, or if there is an even simpler way to trigger the resize that you can think of. I'm happy to test any ideas out locally if you need as well.

:question: No SVG output when using Cairo operator (SCREEN)?

Hello 👋

I'm getting started with Matplotlib, and working on some dataviz personal project. For this purpose I wanted to use specific operators, such as SCREEN, on drawn polygons.

Result is fine, but I'm having an issue (?) when I want to save (using plt.savefig()) my figure to SVG format: without operator SVG output is just fine, but with SCREEN operator (or others...) I get a wrapped PNG (inside a <image />). Is this expected?

As I said, I'm getting started with Matplotlib, custom backend and also Python (!), so maybe there is something I'm missing here, or doing wrong? Anyway, any help would be really great!

Thx in advance 🙏

Sample code (from actual local code):

import matplotlib
from matplotlib import cm
from matplotlib import colors
from matplotlib import pyplot as plt

matplotlib.use("module://mplcairo.qt")
from mplcairo import operator_t

import numpy as np

def draw(axe, frame, frameset, cmap, operator=None):
  theta = np.linspace(0, 2 * np.pi, len(frame), endpoint=False)
  norm = colors.Normalize(vmin=np.min(frameset), vmax=np.max(frameset))

  d = np.append(frame, frame[:1])
  a = np.append(theta, theta[:1])

  r = np.power(d, 1/2) # re-scaled radii
  c = cmap(norm(np.mean(d))) # re-scaled colors

  polygons = axe.fill(a, r, facecolor=c, linewidth=0.75, alpha=0.5)

  # Optional operator
  if operator:
    for p in polygons:
      # See https://cairographics.org/operators/
      operator_t[operator].patch_artist(p)

# Let's plot!
fig = plt.figure(figsize=(8,8))
ax = fig.add_subplot(projection='polar')
# Reset angle starting point and direction
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
# Remove grid and ticks
ax.set_axis_off()
# The figure patch should be fully transparent to avoid
# compositing the patches against it
fig.patch.set(alpha=0)

frames = [[0, 2, 4], [1, 3, 5], [2, 4, 6]] # np.ndarray
  
for f in frames:
  draw(ax, f, frames, cm.get_cmap('Reds'), 'SCREEN')

plt.tight_layout()
plt.savefig('test.svg', format='svg')

Result of mplcairo.get_versions():

{
  'python': '3.8.5 (default, Sep  4 2020, 07:30:14) \n[GCC 7.3.0]',
  'mplcairo': '0.4',
  'matplotlib': '3.4.2',
  'cairo': '1.16.0',
  'freetype': '2.10.4',
  'pybind11': '2.6.2',
  'raqm': None,
  'hb': None
}

[REQUEST] Jupyter Inline Plots

When I use the mplcairo backend, my plots do not appear inline in Jupyter (I'm not talking about the inline widget here, just inline PNGs).
Is there anyway to get the inline PNGs, given Cairo supports PNG export anyway?

Printing of Tamil language characters

Output of mplcairo.get_versions()
{'python': '3.9.12 (main, Jun 1 2022, 11:38:51) \n[GCC 7.5.0]', 'mplcairo': '0.5', 'matplotlib': '3.5.3', 'cairo': '1.16.0', 'freetype': '2.11.0', 'pybind11': '2.10.0', 'raqm': None, 'hb': None}

c907b492-c814-43e6-8bf4-7657926eff41

The tamil words in x-axis are not printed correctly.
Eg:- சொல்லுங்க

  1. Will mplcairo resolve this ?

Segfault on Linux when matplotlib.rcParams["agg.path.chunksize"] = 1000 enabled

double free or corruption (!prev)

I use matplotlib to render a series of video frames. I tried but failed to create a simplified example.

Test case?

I think I've found the single input which causes Cairo to fail (1764 lines): https://gist.github.com/jimbo1qaz/a4e6d682343ac991425e522dd5667262#file-data-py

I was only able to make my full program crash, not any smaller test case.

agg.path.chunksize is 1000. Removing or changing value of parameter seems to make bug not happen. Changing render resolution (originally 1280x720) causes bug to disappear or symptoms to change (corrupted size vs. prev_size, free(): invalid next size (normal)...). But given a fixed environment, bug happens on the same (or similar) frame of input every time.

gdb backtrace

https://gist.github.com/jimbo1qaz/a4e6d682343ac991425e522dd5667262#file-0-gdb-bt

valgrind python -m corrscope

https://gist.github.com/jimbo1qaz/a4e6d682343ac991425e522dd5667262

wow, valgrind is slow. FPS = 2.5168215886315983

Version

Kubuntu 18.04, Python 3.7.2 compiled via pyenv.

apt show libcairo2
Package: libcairo2
Version: 1.15.10-2

pip show mplcairo
Name: mplcairo
Version: 0.1

bug still happens on mplcairo-0.1.post63+g17c19d9

Do you think it's an upstream/libcairo bug?

Crash on import

Not sure what's triggering it as there's not much else printed out:

$ PYTHONPATH=/builddir/build/BUILDROOT/python-mplcairo-0.1-0.2.a1.fc29.x86_64/usr/lib64/python3.6/site-packages  /usr/bin/python3 -c 'import mplcairo.base'
terminate called after throwing an instance of 'pybind11::error_already_set'
  what():  SystemError: <built-in method __contains__ of dict object at 0x7f05392dc480> returned a result with an error set
/var/tmp/rpm-tmp.AHgxop: line 33:   311 Aborted                 (core dumped) PYTHONPATH="/builddir/build/BUILDROOT/python-mplcairo-0.1-0.2.a1.fc29.x86_64/usr/lib64/python3.6/site-packages" /usr/bin/python3 -c 'import mplcairo.base'

using pybind11 2.2.2, cairo 1.15.12, and python 3.6.5.

Gtk backend cut off / incorrect coordinates

I'm trying to use the latest version (f7b0054) of mplcairo with the GTK3 backend. The canvas is contained on a page with multiple other widgets. What I see is that the plot is cut off, about 1/4th to 1/5th of the height is actually shown, and around 4/5 of the width. The plot contains a matplotlib multi-cursor, when moving it around the coordinates also don't match the mouse, there's a quite large offset in both x and y directions.

matplotlib has been installed according to your documentation, including the PRs, mplcairo has been installed from source. Please let me know if you need further information or would like me to try something for debugging.

Thanks!

matplotlib inline support for JupyterLab

Versions Information

>>> import mplcairo
>>> mplcairo.get_versions()
{'python': '3.9.5 (default, Jun  4 2021, 12:28:51) \n[GCC 7.5.0]', 'mplcairo': '0.4', 'matplotlib': '3.5.1', 'cairo': '1.16.0', 'freetype': '2.10.1', 'pybind11': '2.6.2', 'raqm': None, 'hb': None}

Problem Specification

I was trying to use mplcairo as my backend for Matplotlib plotting with custom .otf font (Source Han Serif SC, a popular CJK font). Here is my code:

import matplotlib
print("matplotlib.__version__:", matplotlib.__version__)
print('Default backend:', matplotlib.get_backend())
matplotlib.use("module://mplcairo.base")
# matplotlib.use("Cairo")
print('Backend is now:', matplotlib.get_backend())
import matplotlib.font_manager as fm
import matplotlib.pyplot as plt
matplotlib.rcParams['pdf.fonttype'] = 42
matplotlib.rcParams['ps.fonttype'] = 42


FIG_SIZE = (8,4.5)
DPI = 120
CHINESE_FP = fm.FontProperties(fname='./font/source_han_serif_sc_regular.otf', math_fontfamily="stix")


fig, ax = plt.subplots(figsize=FIG_SIZE, dpi=DPI)
ax.set_xlabel(r'测试中文字体 Normal', fontsize=28.0, fontweight="normal", fontproperties=CHINESE_FP)
ax.set_ylabel(r'测试中文字体 Bold', fontsize=28.0, fontweight="bold", fontproperties=CHINESE_FP)
# Save the figure
fig.savefig('./cjk_font_test.pdf', format='pdf', bbox_inches='tight')
fig.savefig('./cjk_font_test.eps', format='eps', bbox_inches='tight')
fig.savefig('./cjk_font_test.png', format='png', bbox_inches='tight')

print("Figures saved!")

In order to enable Matplotlib inline plotting with the mplcairo backend in JupyterLab, I tried adding the following code snippet (copied from the README of mplcairo) in my JupyterLab config file (jupyterlab_config.py):

import mplcairo.base
import ipykernel.pylab.backend_inline
ipykernel.pylab.backend_inline.new_figure_manager = mplcairo.base.new_figure_manager

I started my JupyterLab using the following command:

$ jupyter lab --config jupyterlab_config.py

This config did not work. I can save figures successfully, but there is no inline figure in the notebook. After searching for a while, I found that ipykernel.pylab.backend_inline is deprecated, matplotlib_inline.backend_inline should be used instead (see this commit). Thus, I tried the following config as well:

import mplcairo.base
import matplotlib_inline.backend_inline
matplotlib_inline.backend_inline.new_figure_manager = mplcairo.base.new_figure_manager

However, this did not work neither. I've read through the documentation and the webpages I can found. Hope mplcairo can be used in JupyterLab with inline support. Thanks for your awesome library!

Python 3.10 wheels and compatibility

Hi I tried to install mplcairo on Python 3.10 but discovered there is no wheels for it and when attempting to build one I met the following nasty traceback:

Collecting mplcairo
  Downloading mplcairo-0.4.tar.gz (92 kB)
     ---------------------------------------- 92.2/92.2 kB 1.7 MB/s eta 0:00:00
  Preparing metadata (setup.py) ... done
Collecting matplotlib>=2.2
  Downloading matplotlib-3.5.3-cp310-cp310-win_amd64.whl (7.2 MB)
     ---------------------------------------- 7.2/7.2 MB 51.0 MB/s eta 0:00:00
Collecting pillow
  Downloading Pillow-9.2.0-cp310-cp310-win_amd64.whl (3.3 MB)
     ---------------------------------------- 3.3/3.3 MB 69.5 MB/s eta 0:00:00
Requirement already satisfied: packaging>=20.0 in c:\users\matthieu.dartiailh\anaconda3\envs\py310\lib\site-packages (from matplotlib>=2.2->mplcairo) (21.0)
Requirement already satisfied: kiwisolver>=1.0.1 in c:\users\matthieu.dartiailh\anaconda3\envs\py310\lib\site-packages (from matplotlib>=2.2->mplcairo) (1.3.2)
Collecting cycler>=0.10
  Using cached cycler-0.11.0-py3-none-any.whl (6.4 kB)
Requirement already satisfied: numpy>=1.17 in c:\users\matthieu.dartiailh\anaconda3\envs\py310\lib\site-packages (from matplotlib>=2.2->mplcairo) (1.21.4)
Collecting fonttools>=4.22.0
  Downloading fonttools-4.34.4-py3-none-any.whl (944 kB)
     ---------------------------------------- 944.1/944.1 kB ? eta 0:00:00
Requirement already satisfied: pyparsing>=2.2.1 in c:\users\matthieu.dartiailh\anaconda3\envs\py310\lib\site-packages (from matplotlib>=2.2->mplcairo) (2.4.7)
Collecting python-dateutil>=2.7
  Using cached python_dateutil-2.8.2-py2.py3-none-any.whl (247 kB)
Requirement already satisfied: six>=1.5 in c:\users\matthieu.dartiailh\anaconda3\envs\py310\lib\site-packages (from python-dateutil>=2.7->matplotlib>=2.2->mplcairo) (1.16.0)
Building wheels for collected packages: mplcairo
  Building wheel for mplcairo (setup.py) ... error
  error: subprocess-exited-with-error

  × python setup.py bdist_wheel did not run successfully.
  │ exit code: 1
  ╰─> [31 lines of output]
      C:\Users\matthieu.dartiailh\Anaconda3\envs\py310\lib\site-packages\setuptools\installer.py:27: SetuptoolsDeprecationWarning: setuptools.installer is deprecated. Requirements should be satisfied by a PEP 517 installer.
        warnings.warn(
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build\lib.win-amd64-cpython-310
      creating build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\base.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\gtk.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\gtk_native.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\macosx.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\multipage.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\qt.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\tk.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\wx.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\_backports.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\_util.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\_version.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\__init__.py -> build\lib.win-amd64-cpython-310\mplcairo
      running build_ext
      building 'mplcairo._mplcairo' extension
      creating build\temp.win-amd64-cpython-310
      creating build\temp.win-amd64-cpython-310\Release
      creating build\temp.win-amd64-cpython-310\Release\src
      "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.28.29910\bin\HostX86\x64\cl.exe" /c /nologo /O2 /W3 /GL /DNDEBUG /MD -IC:\Users\matthieu.dartiailh\AppData\Local\Temp\pip-install-cryzp84l\mplcairo_8b94e57afec74d049241a90dd713db7f\.eggs\pycairo-1.21.0-py3.10-win-amd64.egg\cairo\include -Ic:\users\matthieu.dartiailh\appdata\local\temp\pip-install-cryzp84l\mplcairo_8b94e57afec74d049241a90dd713db7f\.eggs\pybind11-2.10.0-py3.10.egg\pybind11\include -Ibuild\include -IC:\Users\matthieu.dartiailh\Anaconda3\envs\py310\Library\include -IC:\Users\matthieu.dartiailh\Anaconda3\envs\py310\include -IC:\Users\matthieu.dartiailh\Anaconda3\envs\py310\Include "-IC:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.28.29910\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\cppwinrt" /EHsc /Tpsrc/_unity_build.cpp /Fobuild\temp.win-amd64-cpython-310\Release\src/_unity_build.obj /EHsc /bigobj /std:c++17 /experimental:preprocessor /wd4244 /wd4267
      cl : Command line warning D9035 : option 'experimental:preprocessor' has been deprecated and will be removed in a future release
      cl : Command line warning D9036 : use 'Zc:preprocessor' instead of 'experimental:preprocessor'
      _unity_build.cpp
      C:\Users\matthieu.dartiailh\AppData\Local\Temp\pip-install-cryzp84l\mplcairo_8b94e57afec74d049241a90dd713db7f\src\_feature_tests.cpp(6): fatal error C1083: Cannot open include file: 'cairo.h': No such file or directory
      error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\bin\\HostX86\\x64\\cl.exe' failed with exit code 2
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for mplcairo
  Running setup.py clean for mplcairo
Failed to build mplcairo
Installing collected packages: python-dateutil, pillow, fonttools, cycler, matplotlib, mplcairo
  Running setup.py install for mplcairo ... error
  error: subprocess-exited-with-error

  × Running setup.py install for mplcairo did not run successfully.
  │ exit code: 1
  ╰─> [32 lines of output]
      C:\Users\matthieu.dartiailh\Anaconda3\envs\py310\lib\site-packages\setuptools\installer.py:27: SetuptoolsDeprecationWarning: setuptools.installer is deprecated. Requirements should be satisfied by a PEP 517 installer.
        warnings.warn(
      running install
      C:\Users\matthieu.dartiailh\Anaconda3\envs\py310\lib\site-packages\setuptools\command\install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
        warnings.warn(
      running build
      running build_py
      creating build\lib.win-amd64-cpython-310
      creating build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\base.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\gtk.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\gtk_native.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\macosx.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\multipage.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\qt.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\tk.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\wx.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\_backports.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\_util.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\_version.py -> build\lib.win-amd64-cpython-310\mplcairo
      copying lib\mplcairo\__init__.py -> build\lib.win-amd64-cpython-310\mplcairo
      running build_ext
      building 'mplcairo._mplcairo' extension
      creating build\temp.win-amd64-cpython-310
      creating build\temp.win-amd64-cpython-310\Release
      creating build\temp.win-amd64-cpython-310\Release\src
      "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.28.29910\bin\HostX86\x64\cl.exe" /c /nologo /O2 /W3 /GL /DNDEBUG /MD -IC:\Users\matthieu.dartiailh\AppData\Local\Temp\pip-install-cryzp84l\mplcairo_8b94e57afec74d049241a90dd713db7f\.eggs\pycairo-1.21.0-py3.10-win-amd64.egg\cairo\include -Ic:\users\matthieu.dartiailh\appdata\local\temp\pip-install-cryzp84l\mplcairo_8b94e57afec74d049241a90dd713db7f\.eggs\pybind11-2.10.0-py3.10.egg\pybind11\include -Ibuild\include -IC:\Users\matthieu.dartiailh\Anaconda3\envs\py310\Library\include -IC:\Users\matthieu.dartiailh\Anaconda3\envs\py310\include -IC:\Users\matthieu.dartiailh\Anaconda3\envs\py310\Include "-IC:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.28.29910\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\cppwinrt" /EHsc /Tpsrc/_unity_build.cpp /Fobuild\temp.win-amd64-cpython-310\Release\src/_unity_build.obj /EHsc /bigobj /std:c++17 /experimental:preprocessor /wd4244 /wd4267
      cl : Command line warning D9035 : option 'experimental:preprocessor' has been deprecated and will be removed in a future release
      cl : Command line warning D9036 : use 'Zc:preprocessor' instead of 'experimental:preprocessor'
      _unity_build.cpp
      C:\Users\matthieu.dartiailh\AppData\Local\Temp\pip-install-cryzp84l\mplcairo_8b94e57afec74d049241a90dd713db7f\src\_feature_tests.cpp(6): fatal error C1083: Cannot open include file: 'cairo.h': No such file or directory
      error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\14.28.29910\\bin\\HostX86\\x64\\cl.exe' failed with exit code 2
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
error: legacy-install-failure

× Encountered error while trying to install package.
╰─> mplcairo

note: This is an issue with the package mentioned above, not pip.
hint: See above for output from the failure.

Is there any interest in updating the install procedure to support PEP517 and produce wheels for Python 3.10 ? Or did this work land somehow in matplotlib and this library is not really needed anymore ?

ImportError: cannot import name '_mplcairo' from partially initialized module 'mplcairo'

I recently installed mplcairo 0.5 on MacOS with pip install mplcairo. However, when I try to import it, I get:

In [1]: import mplcairo
---------------------------------------------------------------------------
ImportError                               Traceback (most recent call last)
Cell In[1], line 1
----> 1 import mplcairo

File ~/packages/macports/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/mplcairo/__init__.py:27
     23     _load_symbols()
     25 import matplotlib as mpl
---> 27 from . import _mplcairo
     28 from ._mplcairo import antialias_t, operator_t, get_options, set_options
     30 __all__ = [
     31     "antialias_t", "operator_t",
     32     "get_options", "set_options",
     33     "get_raw_buffer",
     34 ]

ImportError: cannot import name '_mplcairo' from partially initialized module 'mplcairo' (most likely due to a circular import) (/Users/sbasu1/packages/macports/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/mplcairo/__init__.py)

I am using python 3.11.5.

Will not compile on OS X 10.13

I am trying to installing mplcairo via

brew install pkg-config libffi cairo py3cairo
LIBFFI_PC_PATH=`locate libffi.pc | grep usr | head -n 1`
LIBFFI_PKGCONFIG_PATH=`dirname "$LIBFFI_PC_PATH"`
export PKG_CONFIG_PATH="$LIBFFI_PKGCONFIG_PATH"
pip install mplcairo

but I get

src/_mplcairo.cpp:42:3: error: call to unavailable function 'visit': introduced in macOS 10.14
      std::visit([&](auto const& aa) -> void {
      ^~~~~~~~~~
    /Library/Developer/CommandLineTools/usr/include/c++/v1/variant:1524:26: note: candidate function [with _Visitor = (lambda at src/_mplcairo.cpp:42:14), _Vs = <const std::__1::variant<_cairo_antialias, bool> &>] has been explicitly made unavailable
    constexpr decltype(auto) visit(_Visitor&& __visitor, _Vs&&... __vs) {

I am actually running OS X 10.13. Is it possible to install mplcairo on this version?
Just in case, I am on Python 3.7.

segmentation fault on macOS in drawing text using mplcairo

The script I try to reproduce is

import faulthandler; faulthandler.enable()
# Set the backend to use mplcairo
import platform
print(platform.mac_ver())
import matplotlib, mplcairo
print(mplcairo.get_versions())
print('Default backend: ' + matplotlib.get_backend()) 
matplotlib.use("module://mplcairo.macosx")
print('Backend is now ' + matplotlib.get_backend())

# IMPORTANT: Import these libraries only AFTER setting the backend
import matplotlib.pyplot as plt, numpy as np
# plt.set_loglevel("debug")
from matplotlib.font_manager import FontProperties

# Load Apple Color Emoji font 
prop = FontProperties(fname='./Apple Color Emoji.ttc')

# Set up plot
freqs = [301, 96, 53, 81, 42]
labels = ['😊', '😱', '😂', '😄', '😛']
plt.figure(figsize=(12,8))
p1 = plt.bar(np.arange(len(labels)), freqs, 0.8, color="lightblue")
plt.ylim(0, plt.ylim()[1]+30)

# Make labels
for rect1, label in zip(p1, labels):
    height = rect1.get_height()
    plt.annotate(
        label,
        (rect1.get_x() + rect1.get_width()/2, height+5),
        ha="center",
        va="bottom",
        fontsize=30,
        fontproperties=prop
    )

# plt.show()

plt.savefig("e.png")

The output I got is:

('10.15.1', ('', '', ''), 'x86_64')
{'python': '3.7.4 (default, Sep  7 2019, 18:27:02) \n[Clang 10.0.1 (clang-1001.0.46.4)]', 'mplcairo': '0.2', 'matplotlib': '3.1.1', 'cairo': '1.16.0', 'freetype': '2.6.1', 'pybind11': '2.4.2'}
Default backend: MacOSX
Backend is now module://mplcairo.macosx
Fatal Python error: Segmentation fault

Current thread 0x0000000108a99dc0 (most recent call first):
  File "/usr/local/lib/python3.7/site-packages/matplotlib/text.py", line 291 in _get_layout
  File "/usr/local/lib/python3.7/site-packages/matplotlib/text.py", line 890 in get_window_extent
  File "/usr/local/lib/python3.7/site-packages/matplotlib/axis.py", line 1150 in <listcomp>
  File "/usr/local/lib/python3.7/site-packages/matplotlib/axis.py", line 1150 in _get_tick_bboxes
  File "/usr/local/lib/python3.7/site-packages/matplotlib/axis.py", line 1205 in draw
  File "/usr/local/lib/python3.7/site-packages/matplotlib/artist.py", line 38 in draw_wrapper
  File "/usr/local/lib/python3.7/site-packages/matplotlib/image.py", line 135 in _draw_list_compositing_images
  File "/usr/local/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 2647 in draw
  File "/usr/local/lib/python3.7/site-packages/matplotlib/artist.py", line 38 in draw_wrapper
  File "/usr/local/lib/python3.7/site-packages/matplotlib/image.py", line 135 in _draw_list_compositing_images
  File "/usr/local/lib/python3.7/site-packages/matplotlib/figure.py", line 1709 in draw
  File "/usr/local/lib/python3.7/site-packages/matplotlib/artist.py", line 38 in draw_wrapper
  File "/usr/local/lib/python3.7/site-packages/mplcairo/base.py", line 211 in _get_cached_or_new_renderer
  File "/usr/local/lib/python3.7/site-packages/mplcairo/base.py", line 219 in get_renderer
  File "/usr/local/lib/python3.7/site-packages/mplcairo/base.py", line 319 in _get_fresh_straight_rgba8888
  File "/usr/local/lib/python3.7/site-packages/mplcairo/base.py", line 337 in print_png
  File "/usr/local/lib/python3.7/site-packages/matplotlib/backend_bases.py", line 2082 in print_figure
  File "/usr/local/lib/python3.7/site-packages/mplcairo/base.py", line 236 in print_figure
  File "/usr/local/lib/python3.7/site-packages/matplotlib/figure.py", line 2180 in savefig
  File "/usr/local/lib/python3.7/site-packages/matplotlib/pyplot.py", line 722 in savefig
  File "emojis_plotted_complete_code.py", line 40 in <module>
[1]    14366 segmentation fault  python3 emojis_plotted_complete_code.py

Some modification I made different from issue17 is:

  • I moved Apple Color Emoji.ttc to cwd but to avoid some permission restriction, but it does not help.
  • I tested on using plt.set_loglevel("debug") but the output is not helpful so I comment it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.