Skip to content

Commit 0aadbc7

Browse files
authored
Merge branch 'main' into validate-colors-mutating-input
2 parents 8155228 + eee6efc commit 0aadbc7

7 files changed

Lines changed: 75 additions & 40 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1616
- Fix `mpl_to_plotly` dropping matplotlib stairs plots by rendering `StepPatch` artists as step lines or filled step areas from their path vertices and edge style [[#5698](https://github.com/plotly/plotly.py/pull/5698)], with thanks to @robertoffmoura for the contribution!
1717
- Fix `mpl_to_plotly` showing unwanted legends with placeholder or internal label entries (`_nolegend_`, `_childN`) by defaulting `layout.showlegend=False` unless the matplotlib figure explicitly defines a legend [[#5699](https://github.com/plotly/plotly.py/pull/5699)], with thanks to @robertoffmoura for the contribution!
1818
- Fix `mpl_to_plotly` crashing on figures with fully transparent or alpha-carrying colors, such as boxplot outlier markers (`facecolor="none"`), rgba line colors, and `color="none"` text and axis labels; all matplotlib colors are now exported through a single helper that maps `"none"` to transparent rgba and keeps or overrides alpha as matplotlib does [[#5700](https://github.com/plotly/plotly.py/pull/5700)], with thanks to @robertoffmoura for the contribution!
19+
- Fix serialization of box/lasso select data for figures with multiple subplots [[#5710](https://github.com/plotly/plotly.py/pull/5710)], with thanks to @flpi-sun for the contribution!
1920
- Export tick label colors to the plotly tickfont in `mpl_to_plotly` [[#5716](https://github.com/plotly/plotly.py/pull/5716)], with thanks to @robertoffmoura for the contribution!
2021
- Fix `convert_dash` mapping dotted lines (`linestyle=':'`) to invalid `'circle'` in Plotly, correctly converting them to `'dot'` and preserving custom dash patterns as pixel lists, [[#5719](https://github.com/plotly/plotly.py/pull/5719)] with thanks to @robertoffmoura for the contribution!
2122
- Fix Plotly Express mutating lists passed to the `x` or `y` arguments in wide mode [[#5727](https://github.com/plotly/plotly.py/pull/5727)], with thanks to @cpruijsen for the contribution!
2223
- Fix `px.sunburst`, `px.treemap` and `px.icicle` listing sectors in a different order on every run when `path` is used with a Polars DataFrame; sectors now follow their order of first appearance for all dataframe backends [[#5766](https://github.com/plotly/plotly.py/pull/5766)], with thanks to @Irahan2 for the contribution!
2324
- Fix `mpl_to_plotly` conversion of matplotlib contour lines and line collections: close contour rings ending with `Z` codes, support dash styles, convert date x-axes, separate disjoint subpaths with `None` separators, hide line collection traces from the legend by default, and group consecutive same-style lines into single traces [[#5770](https://github.com/plotly/plotly.py/pull/5770)], with thanks to @robertoffmoura for the contribution!
25+
- Fix `plotly.io.write_images` ignoring `layout.width`/`layout.height` (and the template's) and exporting every figure at the default 700x500 size; it now uses the same width/height priority as `write_image` and `to_image` [[#5784](https://github.com/plotly/plotly.py/pull/5784)], with thanks to @breken-ai for the contribution!
2426
- Fix color utilities mutating the list of colors passed to them [[#5836](https://github.com/plotly/plotly.py/pull/5836)], with thanks to @Enesuygurs for the contribution!
2527

28+
2629
## [7.1.0] - 2026-09-15
2730

2831
### Added

‎doc/python/3d-mesh.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import plotly.graph_objects as go
4242
import numpy as np
4343

4444
# Download data set from plotly repo
45-
pts = np.loadtxt(np.DataSource().open('https://raw.githubusercontent.com/plotly/datasets/master/mesh_dataset.txt'))
45+
pts = np.loadtxt(np.lib.npyio.DataSource().open('https://raw.githubusercontent.com/plotly/datasets/master/mesh_dataset.txt'))
4646
x, y, z = pts.T
4747

4848
fig = go.Figure(data=[go.Mesh3d(x=x, y=y, z=z, color='lightpink', opacity=0.50)])
@@ -58,7 +58,7 @@ The `alphahull` parameter sets the shape of the mesh. If the value is -1 (defaul
5858
import plotly.graph_objects as go
5959
import numpy as np
6060

61-
pts = np.loadtxt(np.DataSource().open('https://raw.githubusercontent.com/plotly/datasets/master/mesh_dataset.txt'))
61+
pts = np.loadtxt(np.lib.npyio.DataSource().open('https://raw.githubusercontent.com/plotly/datasets/master/mesh_dataset.txt'))
6262
x, y, z = pts.T
6363

6464
fig = go.Figure(data=[go.Mesh3d(x=x, y=y, z=z,

‎doc/python/colorscales.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ fig.show()
443443
```python
444444
import plotly.graph_objects as go
445445

446-
import urllib
446+
import urllib.request
447447
import json
448448

449449
response = urllib.request.urlopen(
@@ -535,7 +535,7 @@ Like axes, you can customize the color bar ticks, labels, and values with `ticks
535535
```python
536536
import plotly.graph_objects as go
537537

538-
import urllib
538+
import urllib.request
539539
import json
540540

541541
# Load heatmap data
@@ -570,7 +570,7 @@ By default, color bars are displayed vertically. You can change a color bar to b
570570
```python
571571
import plotly.graph_objects as go
572572

573-
import urllib
573+
import urllib.request
574574
import json
575575

576576
# Load heatmap data
@@ -647,7 +647,7 @@ See the positioning section of [the figure data structure page](/python/figure-s
647647
```python
648648
import plotly.graph_objects as go
649649

650-
import urllib
650+
import urllib.request
651651
import json
652652

653653
# Load heatmap data

‎doc/python/graphing-multiple-chart-types.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ import plotly.graph_objects as go
173173

174174
# Load data
175175
import json
176-
import urllib
176+
import urllib.request
177177

178178
response = urllib.request.urlopen(
179179
"https://raw.githubusercontent.com/plotly/datasets/master/steepest.json")

‎doc/python/sankey-diagram.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ fig.show()
6666

6767
```python
6868
import plotly.graph_objects as go
69-
import urllib, json
69+
import urllib.request, json
7070

7171
url = 'https://raw.githubusercontent.com/plotly/plotly.js/master/test/image/mocks/sankey_energy.json'
7272
response = urllib.request.urlopen(url)
@@ -126,7 +126,7 @@ This example also uses [hovermode](https://plotly.com/python/reference/layout/#l
126126

127127
```python
128128
import plotly.graph_objects as go
129-
import urllib, json
129+
import urllib.request, json
130130

131131
url = 'https://raw.githubusercontent.com/plotly/plotly.js/master/test/image/mocks/sankey_energy.json'
132132
response = urllib.request.urlopen(url)

‎plotly/io/_kaleido.py‎

Lines changed: 42 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,31 @@ def infer_format(path: Union[Path, None], format: Union[str, None]) -> Union[str
9090
return format
9191

9292

93+
def _resolve_width_height(
94+
fig_dict: dict, width: Union[int, None], height: Union[int, None]
95+
) -> tuple:
96+
"""
97+
Return the image width and height to request from Kaleido, in priority order:
98+
the `width`/`height` arguments, then `layout.width`/`layout.height`, then the
99+
template's `layout.width`/`layout.height`, then the plotly.io defaults.
100+
"""
101+
layout = fig_dict.get("layout", {})
102+
template_layout = layout.get("template", {}).get("layout", {})
103+
width = (
104+
width
105+
or layout.get("width")
106+
or template_layout.get("width")
107+
or defaults.default_width
108+
)
109+
height = (
110+
height
111+
or layout.get("height")
112+
or template_layout.get("height")
113+
or defaults.default_height
114+
)
115+
return width, height
116+
117+
93118
def to_image(
94119
fig: Union[dict, plotly.graph_objects.Figure],
95120
format: Union[str, None] = None,
@@ -163,24 +188,7 @@ def to_image(
163188
if defaults.headers:
164189
kopts["headers"] = defaults.headers
165190

166-
width = (
167-
width
168-
or fig_dict.get("layout", {}).get("width")
169-
or fig_dict.get("layout", {})
170-
.get("template", {})
171-
.get("layout", {})
172-
.get("width")
173-
or defaults.default_width
174-
)
175-
height = (
176-
height
177-
or fig_dict.get("layout", {}).get("height")
178-
or fig_dict.get("layout", {})
179-
.get("template", {})
180-
.get("layout", {})
181-
.get("height")
182-
or defaults.default_height
183-
)
191+
width, height = _resolve_width_height(fig_dict, width, height)
184192

185193
img_bytes = kaleido.calc_fig_sync(
186194
fig_dict,
@@ -405,20 +413,23 @@ def write_images(
405413
# We call infer_format() here rather than above so that the `file` argument
406414
# has already been cast to a Path object.
407415
# Also insert defaults for any missing arguments as needed
408-
kaleido_specs = [
409-
dict(
410-
fig=d["fig"],
411-
path=d["file"],
412-
opts=dict(
413-
format=infer_format(d["file"], d["format"]) or defaults.default_format,
414-
width=d["width"] or defaults.default_width,
415-
height=d["height"] or defaults.default_height,
416-
scale=d["scale"] or defaults.default_scale,
417-
),
418-
topojson=defaults.topojson,
416+
kaleido_specs = []
417+
for d in arg_dicts:
418+
width, height = _resolve_width_height(d["fig"], d["width"], d["height"])
419+
kaleido_specs.append(
420+
dict(
421+
fig=d["fig"],
422+
path=d["file"],
423+
opts=dict(
424+
format=infer_format(d["file"], d["format"])
425+
or defaults.default_format,
426+
width=width,
427+
height=height,
428+
scale=d["scale"] or defaults.default_scale,
429+
),
430+
topojson=defaults.topojson,
431+
)
419432
)
420-
for d in arg_dicts
421-
]
422433

423434
from kaleido.errors import ChromeNotFoundError
424435

‎tests/test_optional/test_kaleido/test_kaleido.py‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,24 @@ def test_width_height_priority():
335335
assert height == pio.defaults.default_height, (
336336
"Default height should be used when no layout or argument"
337337
)
338+
339+
340+
def test_write_images_width_height_priority(tmp_path):
341+
"""write_images uses the same width/height priority as to_image:
342+
arguments > layout.width/height > defaults."""
343+
paths = [tmp_path / f"fig{i}.svg" for i in range(3)]
344+
pio.write_images(
345+
[
346+
create_figure(width=800, height=600),
347+
create_figure(width=800, height=600),
348+
create_figure(),
349+
],
350+
paths,
351+
width=[None, 1200, None],
352+
)
353+
dimensions = [parse_svg_dimensions(path.read_bytes()) for path in paths]
354+
assert dimensions[0] == (800, 600), "Layout dimensions should be used"
355+
assert dimensions[1] == (1200, 600), (
356+
"Width argument should override layout, height should use layout"
357+
)
358+
assert dimensions[2] == (pio.defaults.default_width, pio.defaults.default_height)

0 commit comments

Comments
 (0)