Skip to content

Commit 402c9b4

Browse files
authored
Merge pull request #4324 from guyrosin/fix-necessary-columns
Consider necessary columns from complex arguments when interchanging dataframes
2 parents 91060d3 + 1625d35 commit 402c9b4

File tree

3 files changed

+44
-5
lines changed

3 files changed

+44
-5
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## UNRELEASED
6+
7+
### Fixed
8+
- Fixed issue with necessary columns from complex arguments dropped when interchanging dataframes [[#4324](https://github.com/plotly/plotly.py/pull/4324)]
59

610
## [5.16.0] - 2023-08-11
711

packages/python/plotly/plotly/express/_core.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -1419,9 +1419,13 @@ def build_dataframe(args, constructor):
14191419
else:
14201420
# Save precious resources by only interchanging columns that are
14211421
# actually going to be plotted.
1422-
columns = [
1422+
necessary_columns = {
14231423
i for i in args.values() if isinstance(i, str) and i in columns
1424-
]
1424+
}
1425+
for field in args:
1426+
if args[field] is not None and field in array_attrables:
1427+
necessary_columns.update(i for i in args[field] if i in columns)
1428+
columns = list(necessary_columns)
14251429
args["data_frame"] = pd.api.interchange.from_dataframe(
14261430
args["data_frame"].select_columns_by_name(columns)
14271431
)

packages/python/plotly/plotly/tests/test_optional/test_px/test_px_input.py

+34-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from plotly.express._core import build_dataframe
99
from pandas.testing import assert_frame_equal
1010

11+
1112
# Fixtures
1213
# --------
1314
@pytest.fixture
@@ -292,9 +293,10 @@ def __dataframe__(self):
292293
) as mock_from_dataframe:
293294
build_dataframe(args, go.Scatter)
294295
mock_from_dataframe.assert_called_once_with(interchange_dataframe_reduced)
295-
interchange_dataframe.select_columns_by_name.assert_called_with(
296-
["petal_width", "sepal_length"]
297-
)
296+
assert set(interchange_dataframe.select_columns_by_name.call_args[0][0]) == {
297+
"petal_width",
298+
"sepal_length",
299+
}
298300

299301
args = dict(data_frame=input_dataframe_reduced, color=None)
300302
with mock.patch(
@@ -327,6 +329,35 @@ def test_build_df_from_vaex_and_polars(test_lib):
327329
)
328330

329331

332+
@pytest.mark.skipif(
333+
version.parse(pd.__version__) < version.parse("2.0.2"),
334+
reason="plotly doesn't use a dataframe interchange protocol for pandas < 2.0.2",
335+
)
336+
@pytest.mark.parametrize("test_lib", ["vaex", "polars"])
337+
@pytest.mark.parametrize(
338+
"hover_data", [["sepal_width"], {"sepal_length": False, "sepal_width": ":.2f"}]
339+
)
340+
def test_build_df_with_hover_data_from_vaex_and_polars(test_lib, hover_data):
341+
if test_lib == "vaex":
342+
import vaex as lib
343+
else:
344+
import polars as lib
345+
346+
# take out the 'species' columns since the vaex implementation does not cover strings yet
347+
iris_pandas = px.data.iris()[["petal_width", "sepal_length", "sepal_width"]]
348+
iris_vaex = lib.from_pandas(iris_pandas)
349+
args = dict(
350+
data_frame=iris_vaex,
351+
x="petal_width",
352+
y="sepal_length",
353+
hover_data=hover_data,
354+
)
355+
out = build_dataframe(args, go.Scatter)
356+
assert_frame_equal(
357+
iris_pandas.reset_index()[out["data_frame"].columns], out["data_frame"]
358+
)
359+
360+
330361
def test_timezones():
331362
df = pd.DataFrame({"date": ["2015-04-04 19:31:30+1:00"], "value": [3]})
332363
df["date"] = pd.to_datetime(df["date"])

0 commit comments

Comments
 (0)