Skip to content

Commit 5541a79

Browse files
committed
add new API for setting image generation defaults
1 parent 100b955 commit 5541a79

File tree

5 files changed

+137
-17
lines changed

5 files changed

+137
-17
lines changed

plotly/io/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from ._html import to_html, write_html
1818
from ._renderers import renderers, show
1919
from . import base_renderers
20+
from ._defaults import defaults
2021

2122
__all__ = [
2223
"to_image",
@@ -37,6 +38,7 @@
3738
"show",
3839
"base_renderers",
3940
"full_figure_for_development",
41+
"defaults",
4042
]
4143
else:
4244
__all__, __getattr__, __dir__ = relative_import(
@@ -58,6 +60,7 @@
5860
"._html.write_html",
5961
"._renderers.renderers",
6062
"._renderers.show",
63+
"._defaults.defaults",
6164
],
6265
)
6366

plotly/io/_defaults.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Default settings for image generation
2+
3+
4+
class _Defaults(object):
5+
"""
6+
Class to store default settings for image generation.
7+
"""
8+
def __init__(self):
9+
self.default_format = "png"
10+
self.default_width = 700
11+
self.default_height = 500
12+
self.default_scale = 1
13+
14+
defaults = _Defaults()
15+
16+
17+
18+

plotly/io/_kaleido.py

Lines changed: 102 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,32 @@
77

88
import plotly
99
from plotly.io._utils import validate_coerce_fig_to_dict, as_individual_args
10+
from plotly.io import defaults
1011

1112
ENGINE_SUPPORT_TIMELINE = "September 2025"
1213

14+
kaleido_scope_default_getwarning = (
15+
lambda x: f"""
16+
Accessing plotly.io.kaleido.scope.{x} is deprecated and will be removed after {ENGINE_SUPPORT_TIMELINE}.
17+
Please use plotly.io.defaults.{x} instead.
18+
"""
19+
)
20+
21+
kaleido_scope_default_setwarning = (
22+
lambda x: f"""
23+
Setting plotly.io.kaleido.scope.{x} is deprecated and will be removed after {ENGINE_SUPPORT_TIMELINE}. "
24+
Please set plotly.io.defaults.{x} instead.
25+
"""
26+
)
27+
28+
bad_attribute_error = (
29+
lambda x: f"""
30+
Attribute plotly.io.defaults.{x} is not valid.
31+
Also, plotly.io.kaleido.scope.* is deprecated and will be removed after {ENGINE_SUPPORT_TIMELINE}. Please use plotly.io.defaults.* instead.
32+
"""
33+
)
34+
35+
1336
try:
1437
import kaleido
1538

@@ -20,7 +43,28 @@
2043
# Kaleido v0
2144
from kaleido.scopes.plotly import PlotlyScope
2245

23-
scope = PlotlyScope()
46+
# Show a deprecation warning if the old method of setting defaults is used
47+
class PlotlyScopeWithDeprecationWarnings(PlotlyScope):
48+
def __setattr__(self, name, value):
49+
if name in defaults.__dict__:
50+
warnings.warn(
51+
kaleido_scope_default_setwarning(name),
52+
DeprecationWarning,
53+
stacklevel=2,
54+
)
55+
setattr(defaults, name, value)
56+
super(PlotlyScopeWithDeprecationWarnings, self).__setattr__(name, value)
57+
58+
def __getattr__(self, name):
59+
if name in defaults.__dict__:
60+
warnings.warn(
61+
kaleido_scope_default_getwarning(name),
62+
DeprecationWarning,
63+
stacklevel=2,
64+
)
65+
return super(PlotlyScopeWithDeprecationWarnings, self).__getattr__(name)
66+
67+
scope = PlotlyScopeWithDeprecationWarnings()
2468
# Compute absolute path to the 'plotly/package_data/' directory
2569
root_dir = os.path.dirname(os.path.abspath(plotly.__file__))
2670
package_dir = os.path.join(root_dir, "package_data")
@@ -29,6 +73,34 @@
2973
scope.mathjax = (
3074
"https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js"
3175
)
76+
else:
77+
# Kaleido v1
78+
79+
# Show a deprecation warning if the old method of setting defaults is used
80+
class DefaultsDeprecationWarning:
81+
def __getattr__(self, name):
82+
if name in defaults.__dict__:
83+
warnings.warn(
84+
kaleido_scope_default_getwarning(name),
85+
DeprecationWarning,
86+
stacklevel=2,
87+
)
88+
return getattr(defaults, name)
89+
else:
90+
raise AttributeError(bad_attribute_error(name))
91+
92+
def __setattr__(self, name, value):
93+
if name in defaults.__dict__:
94+
warnings.warn(
95+
kaleido_scope_default_setwarning(name),
96+
DeprecationWarning,
97+
stacklevel=2,
98+
)
99+
setattr(defaults, name, value)
100+
else:
101+
raise AttributeError(bad_attribute_error(name))
102+
103+
scope = DefaultsDeprecationWarning()
32104

33105
except ImportError as e:
34106
kaleido_available = False
@@ -64,29 +136,37 @@ def to_image(
64136
- 'pdf'
65137
- 'eps' (Requires the poppler library to be installed and on the PATH)
66138
67-
If not specified, will default to `plotly.io.kaleido.scope.default_format`
139+
If not specified, will default to:
140+
- `plotly.io.defaults.default_format` if engine is "kaleido"
141+
- `plotly.io.orca.config.default_format` if engine is "orca" (deprecated)
68142
69143
width: int or None
70144
The width of the exported image in layout pixels. If the `scale`
71145
property is 1.0, this will also be the width of the exported image
72146
in physical pixels.
73147
74-
If not specified, will default to `plotly.io.kaleido.scope.default_width`
148+
If not specified, will default to:
149+
- `plotly.io.defaults.default_width` if engine is "kaleido"
150+
- `plotly.io.orca.config.default_width` if engine is "orca" (deprecated)
75151
76152
height: int or None
77153
The height of the exported image in layout pixels. If the `scale`
78154
property is 1.0, this will also be the height of the exported image
79155
in physical pixels.
80156
81-
If not specified, will default to `plotly.io.kaleido.scope.default_height`
157+
If not specified, will default to:
158+
- `plotly.io.defaults.default_height` if engine is "kaleido"
159+
- `plotly.io.orca.config.default_height` if engine is "orca" (deprecated)
82160
83161
scale: int or float or None
84162
The scale factor to use when exporting the figure. A scale factor
85163
larger than 1.0 will increase the image resolution with respect
86164
to the figure's layout pixel dimensions. Whereas as scale factor of
87165
less than 1.0 will decrease the image resolution.
88166
89-
If not specified, will default to `plotly.io.kaleido.scope.default_scale`
167+
If not specified, will default to:
168+
- `plotly.io.defaults.default_scale` if engine is "kaliedo"
169+
- `plotly.io.orca.config.default_scale` if engine is "orca" (deprecated)
90170
91171
validate: bool
92172
True if the figure should be validated before being converted to
@@ -174,8 +254,8 @@ def to_image(
174254
if format == "eps":
175255
raise ValueError(
176256
f"""
177-
EPS export is not supported with Kaleido v1. Please use SVG or PDF instead.
178-
You can also downgrade to Kaleido v0, but support for v0 will be removed after {ENGINE_SUPPORT_TIMELINE}.
257+
EPS export is not supported by Kaleido v1. Please use SVG or PDF instead.
258+
You can also downgrade to Kaleido v0, but support for Kaleido v0 will be removed after {ENGINE_SUPPORT_TIMELINE}.
179259
To downgrade to Kaleido v0, run:
180260
$ pip install kaleido<1.0.0
181261
"""
@@ -187,10 +267,10 @@ def to_image(
187267
img_bytes = kaleido.calc_fig_sync(
188268
fig_dict,
189269
opts=dict(
190-
format=format,
191-
width=width,
192-
height=height,
193-
scale=scale,
270+
format=format or defaults.default_format,
271+
width=width or defaults.default_width,
272+
height=height or defaults.default_height,
273+
scale=scale or defaults.default_scale,
194274
),
195275
)
196276
except choreographer.errors.ChromeNotFoundError:
@@ -252,30 +332,36 @@ def write_image(
252332
If not specified and `file` is a string then this will default to the
253333
file extension. If not specified and `file` is not a string then this
254334
will default to:
255-
- `plotly.io.kaleido.scope.default_format` if engine is "kaleido"
256-
- `plotly.io.orca.config.default_format` if engine is "orca"
335+
- `plotly.io.defaults.default_format` if engine is "kaleido"
336+
- `plotly.io.orca.config.default_format` if engine is "orca" (deprecated)
257337
258338
width: int or None
259339
The width of the exported image in layout pixels. If the `scale`
260340
property is 1.0, this will also be the width of the exported image
261341
in physical pixels.
262342
263-
If not specified, will default to`plotly.io.kaleido.scope.default_width`
343+
If not specified, will default to:
344+
- `plotly.io.defaults.default_width` if engine is "kaleido"
345+
- `plotly.io.orca.config.default_width` if engine is "orca" (deprecated)
264346
265347
height: int or None
266348
The height of the exported image in layout pixels. If the `scale`
267349
property is 1.0, this will also be the height of the exported image
268350
in physical pixels.
269351
270-
If not specified, will default to `plotly.io.kaleido.scope.default_height`
352+
If not specified, will default to:
353+
- `plotly.io.defaults.default_height` if engine is "kaleido"
354+
- `plotly.io.orca.config.default_height` if engine is "orca" (deprecated)
271355
272356
scale: int or float or None
273357
The scale factor to use when exporting the figure. A scale factor
274358
larger than 1.0 will increase the image resolution with respect
275359
to the figure's layout pixel dimensions. Whereas as scale factor of
276360
less than 1.0 will decrease the image resolution.
277361
278-
If not specified, will default to `plotly.io.kaleido.scope.default_scale`
362+
If not specified, will default to:
363+
- `plotly.io.defaults.default_scale` if engine is "kaleido"
364+
- `plotly.io.orca.config.default_scale` if engine is "orca" (deprecated)
279365
280366
validate: bool
281367
True if the figure should be validated before being converted to

plotly/io/kaleido.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from ._kaleido import write_image, to_image
1+
from ._kaleido import to_image, write_image, scope

tests/test_optional/test_kaleido/test_kaleido.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,3 +251,16 @@ def test_write_images_multiple(mock_write_image):
251251
]
252252
mock_write_image.assert_has_calls(expected_calls, any_order=False)
253253
assert mock_write_image.call_count == 2
254+
255+
256+
def test_defaults():
257+
"""Test that image output defaults can be set using pio.defaults.*"""
258+
try:
259+
assert pio.defaults.default_format == "png"
260+
pio.defaults.default_format = "svg"
261+
assert pio.defaults.default_format == "svg"
262+
result = pio.to_image(fig, format="svg", validate=False)
263+
assert result.startswith(b"<svg")
264+
finally:
265+
pio.defaults.default_format = "png"
266+
assert pio.defaults.default_format == "png"

0 commit comments

Comments
 (0)