Skip to content

ENH: Plotting support for ExtensionArrays #64300

@Julian-Harbeck

Description

@Julian-Harbeck

Feature Type

  • Adding new functionality to pandas

  • Changing existing functionality in pandas

  • Removing existing functionality in pandas

Problem Description

Plotting of ExtensionArrays is to my knowledge currently only supported for numerical data. Other data is filtered out in the _compute_plot_data function, leading to a TypeError if no numeric data remains:

numeric_data = data.select_dtypes(include=include_type, exclude=exclude_type)
is_empty = numeric_data.shape[-1] == 0
# no non-numeric frames or series allowed
if is_empty:
raise TypeError("no numeric data to plot")

I am currently working on an astropy ExtensionArray. astropy offers its own matplotlib.units.ConversionInterface usable via the quantity_support context manager. I am going more into detail in the dedicated issue of the EA (Julian-Harbeck/pandas-units-extension#4), but basically I would like to do something like this, which currently leads to the TypeError mentioned above:

with quantity_support():
    pd.Series([1, 2, 3], dtype="unit[m]").plot()

Another issue in my opinion is that allowed types are defined in two locations.

  1. In _compute_plot_data there is include_type which is later extended for different plot styles:
    include_type = [np.number, "datetime", "datetimetz", "timedelta"]
  2. In convertes.py there is the mapping of classes to the actual converters used by matplotlib:
    def get_pairs() -> list[tuple[type, type[mdates.DateConverter]]]:
    pairs = [
    (Timestamp, DatetimeConverter),
    (Period, PeriodConverter),
    (pydt.datetime, DatetimeConverter),
    (pydt.date, DatetimeConverter),
    (pydt.time, TimeConverter),
    (np.datetime64, DatetimeConverter),
    ]
    return pairs

    These are added to the matplotlib.units.registry by the pandas_converter decorator and the register function:
    def register() -> None:
    pairs = get_pairs()
    for type_, cls in pairs:
    # Cache previous converter if present
    if type_ in munits.registry and not isinstance(munits.registry[type_], cls):
    previous = munits.registry[type_]
    _mpl_units[type_] = previous
    # Replace with pandas converter
    munits.registry[type_] = cls()

Feature Description

ExtensionArrays should be able to indicate to pandas that there data can be plotted via a flag, e.g. plotable = True for the ExtensionDtype. Then the these are somehow added to the include_type list. For example if I manually in debugger alter the include_list to include astropy.units.Quantity objects then the plotting already works

The following points would be needed to discussed:

  1. Registration of the converter, I see the following options with different complexity:
    1. The user is responsible for the registration, for example in the astropy EA case by calling the quantity_support function or doing the plotting within its context manager as shown above.
    2. The ExtensionArray on itself is responsible to register its ConversionInterface to the matplotlib.units.registry.
    3. Within the pandas @register_extension_dtype decorator the registration is done either to the registry directly or to the the list of tuples retrieved by the get_pairs function.
  2. In the _compute_plot_data function the types included into the include_type list depend on the kind of plot, how does the ExtensionArray communicates which kinds are supported.

I would love to hear your opinions on this topic, the proposed implementation and if anyone sees a need for that for other internal or external EAs.

Alternative Solutions

It would be possible to write an additional Series/Frame accessor in each ExtensionArray implementation that supports plotting this specific dtype. However it would include a lot of boilerplate code, the feature described above would offer a more generalized approach and plotting a DataFrame of mixed EAs would likely not be possible.

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions