Skip to content

Commit

Permalink
Add ppi argument for saving and displaying charts as PNG images (#3163)
Browse files Browse the repository at this point in the history
* Bump min vl-convert-python version to 0.13.0 for ppi support

* Pass ppi argument to vl-convert and specify correct image width/height for display in jupyter

* add comment on 72

* Add changelog entry

* Remove note about vl-convert not being available on Apple Silicon from conda-forge

* Add ppi to chart save documentation
  • Loading branch information
jonmmease authored Aug 25, 2023
1 parent 49b2cfe commit 45cd440
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 19 deletions.
2 changes: 1 addition & 1 deletion altair/utils/_importers.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def import_vegafusion() -> ModuleType:


def import_vl_convert() -> ModuleType:
min_version = "0.12.0"
min_version = "0.13.0"
try:
version = importlib_version("vl-convert-python")
if Version(version) < Version(min_version):
Expand Down
27 changes: 24 additions & 3 deletions altair/utils/mimebundle.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .html import spec_to_html
import struct


def spec_to_mimebundle(
Expand Down Expand Up @@ -121,18 +122,28 @@ def _spec_to_mimebundle_with_engine(spec, format, mode, **kwargs):
svg = vlc.vegalite_to_svg(spec, vl_version=vl_version)
return {"image/svg+xml": svg}
elif format == "png":
scale = kwargs.get("scale_factor", 1)
# The default ppi for a PNG file is 72
default_ppi = 72
ppi = kwargs.get("ppi", default_ppi)
if mode == "vega":
png = vlc.vega_to_png(
spec,
scale=kwargs.get("scale_factor", 1),
scale=scale,
ppi=ppi,
)
else:
png = vlc.vegalite_to_png(
spec,
vl_version=vl_version,
scale=kwargs.get("scale_factor", 1),
scale=scale,
ppi=ppi,
)
return {"image/png": png}
factor = ppi / default_ppi
w, h = _pngxy(png)
return {"image/png": png}, {
"image/png": {"width": w / factor, "height": h / factor}
}
else:
# This should be validated above
# but raise exception for the sake of future development
Expand Down Expand Up @@ -213,3 +224,13 @@ def _validate_normalize_engine(engine, format):
)
)
return normalized_engine


def _pngxy(data):
"""read the (width, height) from a PNG header
Taken from IPython.display
"""
ihdr = data.index(b"IHDR")
# next 8 bytes are width/height
return struct.unpack(">ii", data[ihdr + 4 : ihdr + 12])
2 changes: 1 addition & 1 deletion altair/utils/save.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def perform_save():
**kwargs,
)
if format == "png":
write_file_or_filename(fp, mimebundle["image/png"], mode="wb")
write_file_or_filename(fp, mimebundle[0]["image/png"], mode="wb")
elif format == "pdf":
write_file_or_filename(fp, mimebundle["application/pdf"], mode="wb")
else:
Expand Down
1 change: 1 addition & 0 deletions doc/releases/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Enhancements
- Support grouped bars inside time axis with time bins (see `Vega-Lite Release Notes <https://github.com/vega/vega-lite/releases/tag/v5.9.0>`_)
- Add new transform method `transform_extent` (#3148)
- Add support for new referencing logic in version 4.18 of the jsonschema package
- Add configurable pixels-per-inch (ppi) metadata to saved and displayed PNG images (#3163)

Bug Fixes
~~~~~~~~~
Expand Down
29 changes: 16 additions & 13 deletions doc/user_guide/saving_charts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -171,11 +171,6 @@ or::

pip install vl-convert-python

.. note::

Conda packages are not yet available for the Apple Silicon architecture.
See `conda-forge/vl-convert-python-feedstock#9 <https://github.com/conda-forge/vl-convert-python-feedstock/issues/9>`_.

Unlike altair_saver_, vl-convert_ does not require any external dependencies.
However, it only supports saving charts to PNG and SVG formats. To save directly to
PDF, altair_saver_ is still required. See the vl-convert documentation for information
Expand Down Expand Up @@ -210,17 +205,25 @@ installed you can use::
chart.save('chart.png', engine="altair_saver")


Figure Size/Resolution
^^^^^^^^^^^^^^^^^^^^^^
When using ``chart.save()`` above, the resolution of the resulting PNG is
controlled by the resolution of your screen. The easiest way to produce a
higher-resolution PNG image is to scale the image to make it larger, and thus
to contain more pixels at a given resolution.
PNG Figure Size/Resolution
^^^^^^^^^^^^^^^^^^^^^^^^^^
When using ``chart.save()`` to create a PNG image, the resolution of the resulting image
defaults to 72 pixels per inch (ppi). To change the resolution of the image, while maintaining
the same physical size, the ``ppi`` argument may be provided to ``chart.save``. For example,
to save the image with a resolution of 200 pixels-per-inch::

chart.save('chart.png', ppi=200)

.. note::

This can be done with the ``scale_factor`` argument, which defaults to 1.0::
The ``ppi`` argument is only supported by the ``vl-convert`` engine. It will be ignored if
the ``altair_saver`` engine is enabled.

chart.save('chart.png', scale_factor=2.0)
To change the physical size of the resulting image while preserving the resolution, the
``scale_factor`` argument may be used. For example, to save the image at double the default
size at the default resolution of 72 ppi::

chart.save('chart.png', scale_factor=2)

.. _vl-convert: https://github.com/vega/vl-convert
.. _altair_saver: http://github.com/altair-viz/altair_saver/
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ dev = [
"pytest-cov",
"m2r",
"vega_datasets",
"vl-convert-python>=0.12.0",
"vl-convert-python>=0.13.0",
"mypy",
"pandas-stubs",
"types-jsonschema",
Expand Down

0 comments on commit 45cd440

Please sign in to comment.