Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Example plot_driver_laptimes.py no longer working with latest Seaborn release #459

Closed
theOehrly opened this issue Oct 5, 2023 · 11 comments
Labels
documentation Improvements or additions to documentation

Comments

@theOehrly
Copy link
Owner

Describe the issue:

With the release of seaborn v0.13.0 the plot_driver_laptimes.py example has stopped working. Everything works perfectly fine with seaborn v0.12.2 without changing anything else.

This problem is somehow related to Seaborn casting the timedelta64 data type internally, and NumPy is unhappy about that.

Reproduce the code example:

-- see examples/plot_driver_laptimes.py --

Error message:

Traceback (most recent call last):
  File "C:\Dateien\Code\Formula1\Fast-F1\examples\plot_driver_laptimes.py", line 35, in <module>
    sns.scatterplot(data=driver_laps,
  File "C:\Dateien\Code\Formula1\Fast-F1\venv39\lib\site-packages\seaborn\relational.py", line 603, in scatterplot
    p = _ScatterPlotter(
  File "C:\Dateien\Code\Formula1\Fast-F1\venv39\lib\site-packages\seaborn\relational.py", line 390, in __init__
    super().__init__(data=data, variables=variables)
  File "C:\Dateien\Code\Formula1\Fast-F1\venv39\lib\site-packages\seaborn\_base.py", line 634, in __init__
    self.assign_variables(data, variables)
  File "C:\Dateien\Code\Formula1\Fast-F1\venv39\lib\site-packages\seaborn\_base.py", line 685, in assign_variables
    self.var_types = {
  File "C:\Dateien\Code\Formula1\Fast-F1\venv39\lib\site-packages\seaborn\_base.py", line 686, in <dictcomp>
    v: variable_type(
  File "C:\Dateien\Code\Formula1\Fast-F1\venv39\lib\site-packages\seaborn\_base.py", line 1523, in variable_type
    if np.isin(vector, [0, 1]).all():
  File "C:\Dateien\Code\Formula1\Fast-F1\venv39\lib\site-packages\numpy\lib\arraysetops.py", line 890, in isin
    return in1d(element, test_elements, assume_unique=assume_unique,
  File "C:\Dateien\Code\Formula1\Fast-F1\venv39\lib\site-packages\numpy\lib\arraysetops.py", line 733, in in1d
    mask |= (ar1 == a)
numpy.core._exceptions._UFuncInputCastingError: Cannot cast ufunc 'equal' input 0 from dtype('<m8[ns]') to dtype('<m8') with casting rule 'same_kind'
@theOehrly theOehrly added the documentation Improvements or additions to documentation label Oct 5, 2023
@theOehrly
Copy link
Owner Author

theOehrly commented Oct 5, 2023

@Casper-Guo you were the one who added this example and I've actually never worked with Seaborn. Do you have time to take a look at this? It's not too urgent really.
Else, I can look into it as well.

Edit: I'll temporarily require seaborn<0.13.0 in requirement-dev.txt so that the CI won't fail.

@Casper-Guo
Copy link
Contributor

Just read Seaborn's release notes and it is not obvious what the breaking change was.

I'll look into this over the weekend.

@Casper-Guo
Copy link
Contributor

Casper-Guo commented Oct 7, 2023

Some of my own visualization code is also failing on Seaborn 0.13.0. The below code works as is at Seaborn 0.12.2 but fails at 0.13.0. Setting mpl_timedelta_support=False is the only change required to fix it. There might be a timple issue in here as well.

import fastf1 as f
import fastf1.plotting as p
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

p.setup_mpl(misc_mpl_mods=False)

# session is the most recent race session
laps = session.laps.pick_wo_box()
event_name = session.event["EventName"]

laps["LapTime (s)"] = laps["LapTime"].dt.total_seconds()
team_order = (
    laps[["Team", "LapTime (s)"]]
    .groupby("Team")
    .median()["LapTime (s)"]
    .sort_values()
    .index
)
team_palette = {team: p.team_color(team) for team in team_order}

fig, ax = plt.subplots(figsize=(15, 10))
sns.boxplot(
    data=laps,
    x="Team",
    y="LapTime (s)",
    order=team_order,
    palette=team_palette,
    whiskerprops=dict(color="white"),
    boxprops=dict(edgecolor="white"),
    medianprops=dict(color="grey"),
    capprops=dict(color="white"),
    showfliers=False,
)
plt.title(f"{CURRENT_SEASON} {event_name}")
plt.grid(visible=False)
ax.set(xlabel=None)

Full trace:

Traceback (most recent call last):
  File "/home/robery/.local/lib/python3.11/site-packages/pandas/core/indexes/base.py", line 3802, in get_loc
    return self._engine.get_loc(casted_key)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "pandas/_libs/index.pyx", line 138, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/index.pyx", line 165, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 2263, in pandas._libs.hashtable.Int64HashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 2273, in pandas._libs.hashtable.Int64HashTable.get_item
KeyError: 0

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/mnt/d/Projects/F1-Visualization/src/readme_update.py", line 91, in <module>
    sns.boxplot(
  File "/home/robery/.local/lib/python3.11/site-packages/seaborn/categorical.py", line 1604, in boxplot
    p._attach(ax, log_scale=log_scale)
  File "/home/robery/.local/lib/python3.11/site-packages/seaborn/_base.py", line 1134, in _attach
    converter.update_units(seed_data)
  File "/home/robery/.local/lib/python3.11/site-packages/matplotlib/axis.py", line 1669, in update_units
    converter = munits.registry.get_converter(data)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/robery/.local/lib/python3.11/site-packages/timple/patches.py", line 121, in get_converter
    if np.iterable(x) and hasattr(x[0], 'value'):
                                  ~^^^
  File "/home/robery/.local/lib/python3.11/site-packages/pandas/core/series.py", line 981, in __getitem__
    return self._get_value(key)
           ^^^^^^^^^^^^^^^^^^^^
  File "/home/robery/.local/lib/python3.11/site-packages/pandas/core/series.py", line 1089, in _get_value
    loc = self.index.get_loc(label)
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/robery/.local/lib/python3.11/site-packages/pandas/core/indexes/base.py", line 3804, in get_loc
    raise KeyError(key) from err
KeyError: 0

@pesaventofilippo can you please also check your code base for any failure at 0.13.0?

@pesaventofilippo
Copy link
Contributor

@Casper-Guo Sure! I just checked, and I have the same problem as you above. Works fine in 0.12.2, but doesn't with 0.13.0.
Even for me, after converting the LapTime to seconds with laps["LapTime"].dt.total_seconds(), the problem remains.

I don't use Seaborn much, so I'm not very familiar with it unfortunately. My only guess is that both Seaborn and FastF1 change the way matplotlib behaves with timedeltas, so maybe they're interfering with each other? A big feature in seaborn 0.13.0 is datetime support.

@Casper-Guo
Copy link
Contributor

The relevant section of the release notes:

The categorical functions have historically treated all data as categorical, even when it has a numeric or datetime type. This can now be controlled with the new native_scale parameter. The default remains False to preserve existing behavior. But with native_scale=True, values will be treated as they would by other seaborn or matplotlib functions. Element widths will be derived from the minimum distance between two unique values on the categorical axis.

Just based on this text, the change might affect my script but shouldn't affect the example. The trace seems to back this up. This may well be two separate issues but I thought I would raise it to provide some clues.

I will try to reduce the example to isolate the error and then maybe open an issue in the Seaborn repo too

@Casper-Guo
Copy link
Contributor

I actually cannot reproduce the reported error currently. I have seaborn 0.13.0 installed in the environment and the script is working as expected.

@theOehrly
Copy link
Owner Author

I will have a look at this later today as well. Including trying to figure out how Timple patching parts of Matplotlib may interfere here.

@theOehrly
Copy link
Owner Author

I've isolated both errors. They are unrelated.

The error in the plot_driver_laptimes.py example is caused by a minor type casting issue/unhandled exception that I'd consider as a bug in Seaborn. I'll likely open a PR tomorrow, after investigation some more small details.

The error in the code that you provided, @Casper-Guo is more or less an oversight in Timple. Seaborn unexpectedly passes Pandas objects to a function that Timple is patching. That will probably be an easy fix, though.

@theOehrly
Copy link
Owner Author

@Casper-Guo the error in your script is fixed with the latest release of timple just now.

To fix the error in plot_driver_laptimes.py I've opened mwaskom/seaborn#3516

@Casper-Guo
Copy link
Contributor

Thank you for doing all the investigation!

@theOehrly
Copy link
Owner Author

Seaborn v0.13.1 has been released two days ago. That means the second error is fixed as well.

I'll require seaborn>0.13.0 for the documentation build from now on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

3 participants