Skip to content

Commit 88a8510

Browse files
authored
Merge branch 'main' into main
2 parents 2562d1e + 4be2983 commit 88a8510

377 files changed

Lines changed: 100696 additions & 99988 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,20 @@ This project adheres to [Semantic Versioning](http://semver.org/).
44

55
## Unreleased
66

7+
## [6.5.2] - 2026-01-14
8+
9+
### Fixed
10+
- Fix issue where pie trace `legend`, `showlegend` attributes don't accept array values [[#5464](https://github.com/plotly/plotly.py/pull/5464) and [#5465](https://github.com/plotly/plotly.py/pull/5465)], with thanks to @my-tien for the contribution!
11+
12+
## [6.5.1] - 2026-01-07
13+
714
### Fixed
8-
- Fix issue where Plotly Express ignored trace-specific color sequences defined in templates via `template.data.<trace_type>` [[#5437](https://github.com/plotly/plotly.py/pull/5437)]
15+
- Fix issue where Plotly Express ignored trace-specific color sequences defined in templates via `template.data.<trace_type>` [[#5437](https://github.com/plotly/plotly.py/pull/5437)], with thanks to @antonymilne for the contribution!
916

1017
### Updated
1118
- Speed up `validate_gantt` function [[#5386](https://github.com/plotly/plotly.py/pull/5386)], with thanks to @misrasaurabh1 for the contribution!
19+
- Update plotly.js from version 3.3.0 to version 3.3.1. See the plotly.js [release notes](https://github.com/plotly/plotly.js/releases/tag/v3.3.1) for more information. [[#5456](https://github.com/plotly/plotly.py/pull/5456)]. Notable changes include:
20+
- Add support for arrays for the pie properties `showlegend` and `legend`, so that these can be configured per slice. [[#7580](https://github.com/plotly/plotly.js/pull/7580)]
1221

1322
## [6.5.0] - 2025-11-17
1423

CITATION.cff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ authors:
99
- family-names: "Parmer"
1010
given-names: "Chris"
1111
title: "An interactive, open-source, and browser-based graphing library for Python"
12-
version: 6.5.0
12+
version: 6.5.2
1313
doi: 10.5281/zenodo.14503524
14-
date-released: 2025-11-17
14+
date-released: 2026-01-14
1515
url: "https://github.com/plotly/plotly.py"

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ npm run build
137137
These commands also create an *editable install* of plotly.py
138138
so that you can test your changes iteratively without having to rebuild the plotly.py package explicitly;
139139
for more information please see
140-
[the `pip` documentation on editable installs](https://pip.pypa.io/en/stable/reference/pip_install/#install-editable)
140+
[the `pip` documentation on editable installs](https://pip.pypa.io/en/stable/topics/local-project-installs/#editable-installs)
141141
Please note that the single quotes are needed to escape the `[]` characters.
142142

143143
### Formatting

_plotly_utils/basevalidators.py

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -632,24 +632,35 @@ class BooleanValidator(BaseValidator):
632632
"description": "A boolean (true/false) value.",
633633
"requiredOpts": [],
634634
"otherOpts": [
635+
"arrayOk",
635636
"dflt"
636637
]
637638
},
638639
"""
639640

640-
def __init__(self, plotly_name, parent_name, **kwargs):
641+
def __init__(self, plotly_name, parent_name, array_ok=False, **kwargs):
641642
super(BooleanValidator, self).__init__(
642643
plotly_name=plotly_name, parent_name=parent_name, **kwargs
643644
)
645+
self.array_ok = array_ok
644646

645647
def description(self):
646-
return """\
647-
The '{plotly_name}' property must be specified as a bool
648-
(either True, or False)""".format(plotly_name=self.plotly_name)
648+
desc = """\
649+
The '{plotly_name}' property is a boolean and must be specified as:
650+
- A boolean value: True or False""".format(plotly_name=self.plotly_name)
651+
if self.array_ok:
652+
desc += """
653+
- A tuple or list of the above"""
654+
return desc
649655

650656
def validate_coerce(self, v):
651657
if is_none_or_typed_array_spec(v):
652658
pass
659+
elif self.array_ok and is_simple_array(v):
660+
invalid_els = [e for e in v if not isinstance(e, bool)]
661+
if invalid_els:
662+
self.raise_invalid_elements(invalid_els[:10])
663+
v = to_scalar_or_list(v)
653664
elif not isinstance(v, bool):
654665
self.raise_invalid_val(v)
655666

@@ -1735,12 +1746,15 @@ class SubplotidValidator(BaseValidator):
17351746
"dflt"
17361747
],
17371748
"otherOpts": [
1749+
"arrayOk",
17381750
"regex"
17391751
]
17401752
}
17411753
"""
17421754

1743-
def __init__(self, plotly_name, parent_name, dflt=None, regex=None, **kwargs):
1755+
def __init__(
1756+
self, plotly_name, parent_name, dflt=None, regex=None, array_ok=False, **kwargs
1757+
):
17441758
if dflt is None and regex is None:
17451759
raise ValueError("One or both of regex and deflt must be specified")
17461760

@@ -1755,40 +1769,55 @@ def __init__(self, plotly_name, parent_name, dflt=None, regex=None, **kwargs):
17551769
self.base = re.match(r"/\^(\w+)", regex).group(1)
17561770

17571771
self.regex = self.base + r"(\d*)"
1772+
self.array_ok = array_ok
17581773

17591774
def description(self):
17601775
desc = """\
17611776
The '{plotly_name}' property is an identifier of a particular
1762-
subplot, of type '{base}', that may be specified as the string '{base}'
1763-
optionally followed by an integer >= 1
1764-
(e.g. '{base}', '{base}1', '{base}2', '{base}3', etc.)
1765-
""".format(plotly_name=self.plotly_name, base=self.base)
1777+
subplot, of type '{base}', that may be specified as:
1778+
- the string '{base}' optionally followed by an integer >= 1
1779+
(e.g. '{base}', '{base}1', '{base}2', '{base}3', etc.)""".format(
1780+
plotly_name=self.plotly_name, base=self.base
1781+
)
1782+
if self.array_ok:
1783+
desc += """
1784+
- A tuple or list of the above"""
17661785
return desc
17671786

17681787
def validate_coerce(self, v):
1769-
if v is None:
1770-
pass
1771-
elif not isinstance(v, str):
1772-
self.raise_invalid_val(v)
1773-
else:
1774-
# match = re.fullmatch(self.regex, v)
1775-
match = fullmatch(self.regex, v)
1788+
def coerce(value):
1789+
if not isinstance(value, str):
1790+
return value, False
1791+
match = fullmatch(self.regex, value)
17761792
if not match:
1777-
is_valid = False
1793+
return value, False
17781794
else:
17791795
digit_str = match.group(1)
17801796
if len(digit_str) > 0 and int(digit_str) == 0:
1781-
is_valid = False
1797+
return value, False
17821798
elif len(digit_str) > 0 and int(digit_str) == 1:
1783-
# Remove 1 suffix (e.g. x1 -> x)
1784-
v = self.base
1785-
is_valid = True
1799+
return self.base, True
17861800
else:
1787-
is_valid = True
1801+
return value, True
17881802

1789-
if not is_valid:
1790-
self.raise_invalid_val(v)
1791-
return v
1803+
if v is None:
1804+
pass
1805+
elif self.array_ok and is_simple_array(v):
1806+
values = []
1807+
invalid_els = []
1808+
for e in v:
1809+
coerced_e, success = coerce(e)
1810+
values.append(coerced_e)
1811+
if not success:
1812+
invalid_els.append(coerced_e)
1813+
if len(invalid_els) > 0:
1814+
self.raise_invalid_elements(invalid_els[:10])
1815+
return values
1816+
else:
1817+
v, success = coerce(v)
1818+
if not success:
1819+
self.raise_invalid_val(self.base)
1820+
return v
17921821

17931822

17941823
class FlaglistValidator(BaseValidator):

0 commit comments

Comments
 (0)