diff --git a/seaborn/_core/data.py b/seaborn/_core/data.py index c17bfe95c5..b17d4fee2e 100644 --- a/seaborn/_core/data.py +++ b/seaborn/_core/data.py @@ -312,6 +312,12 @@ def convert_dataframe_to_pandas(data: object) -> pd.DataFrame: # in Plot.add(). But noting here in case this seems to be a bottleneck. return pd.api.interchange.from_dataframe(data) except Exception as err: + try: + # An object's own to_pandas method may be more flexible than the interchange + # See https://github.com/mwaskom/seaborn/pull/3534 for more context + return data.to_pandas() # type: ignore[attr-defined] + except Exception: + pass msg = ( "Encountered an exception when converting data source " "to a pandas DataFrame. See traceback above for details." diff --git a/tests/_core/test_data.py b/tests/_core/test_data.py index 0e67ed37b4..cf29f98443 100644 --- a/tests/_core/test_data.py +++ b/tests/_core/test_data.py @@ -429,6 +429,19 @@ def test_data_interchange_failure(self, mock_long_df): with pytest.raises(RuntimeError, match="Encountered an exception"): PlotData(mock_long_df, {"x": "x"}) + @pytest.mark.skipif( + condition=not hasattr(pd.api, "interchange"), + reason="Tests behavior assuming support for dataframe interchange" + ) + def test_data_interchange_failure_with_fallback(self, mock_long_df, long_df): + + mock_long_df._data = None # Break __dataframe__() + mock_long_df.to_pandas = lambda: long_df + variables = {"x": "x", "y": "z", "color": "a"} + p = PlotData(mock_long_df, variables) + for var, col in variables.items(): + assert_vector_equal(p.frame[var], long_df[col]) + @pytest.mark.skipif( condition=hasattr(pd.api, "interchange"), reason="Tests graceful failure without support for dataframe interchange"