awkward icon indicating copy to clipboard operation
awkward copied to clipboard

support for matplotlib.pyplot.hist2d with awkward arrays

Open davidlange6 opened this issue 2 months ago • 1 comments

Version of Awkward Array

2.8.9

Description and code to reproduce

Trying to use awkward arrays in matplotlib hist2d does not work

plt.hist2d(ak.flatten(a1),ak.flatten(a1))

results in

AttributeError                            Traceback (most recent call last)
Cell In[6], line 1
----> 1 plt.hist2d(ak.flatten(a1),ak.flatten(a1))

File [~/NSBI-workflow-tutorial/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/matplotlib/_api/deprecation.py:453](https://jupyterhub.ssl-hep.org/user/[email protected]/research-softwa-dia-october2025-47hkxj8t/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/matplotlib/_api/deprecation.py#line=452), in make_keyword_only.<locals>.wrapper(*args, **kwargs)
    447 if len(args) > name_idx:
    448     warn_deprecated(
    449         since, message="Passing the %(name)s %(obj_type)s "
    450         "positionally is deprecated since Matplotlib %(since)s; the "
    451         "parameter will become keyword-only in %(removal)s.",
    452         name=name, obj_type=f"parameter of {func.__name__}()")
--> 453 return func(*args, **kwargs)

File [~/NSBI-workflow-tutorial/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/matplotlib/pyplot.py:3537](https://jupyterhub.ssl-hep.org/user/[email protected]/research-softwa-dia-october2025-47hkxj8t/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/matplotlib/pyplot.py#line=3536), in hist2d(x, y, bins, range, density, weights, cmin, cmax, data, **kwargs)
   3523 @_copy_docstring_and_deprecators(Axes.hist2d)
   3524 def hist2d(
   3525     x: ArrayLike,
   (...)   3535     **kwargs,
   3536 ) -> tuple[np.ndarray, np.ndarray, np.ndarray, QuadMesh]:
-> 3537     __ret = gca().hist2d(
   3538         x,
   3539         y,
   3540         bins=bins,
   3541         range=range,
   3542         density=density,
   3543         weights=weights,
   3544         cmin=cmin,
   3545         cmax=cmax,
   3546         **({"data": data} if data is not None else {}),
   3547         **kwargs,
   3548     )
   3549     sci(__ret[-1])
   3550     return __ret

File [~/NSBI-workflow-tutorial/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/matplotlib/_api/deprecation.py:453](https://jupyterhub.ssl-hep.org/user/[email protected]/research-softwa-dia-october2025-47hkxj8t/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/matplotlib/_api/deprecation.py#line=452), in make_keyword_only.<locals>.wrapper(*args, **kwargs)
    447 if len(args) > name_idx:
    448     warn_deprecated(
    449         since, message="Passing the %(name)s %(obj_type)s "
    450         "positionally is deprecated since Matplotlib %(since)s; the "
    451         "parameter will become keyword-only in %(removal)s.",
    452         name=name, obj_type=f"parameter of {func.__name__}()")
--> 453 return func(*args, **kwargs)

File [~/NSBI-workflow-tutorial/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/matplotlib/__init__.py:1524](https://jupyterhub.ssl-hep.org/user/[email protected]/research-softwa-dia-october2025-47hkxj8t/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/matplotlib/__init__.py#line=1523), in _preprocess_data.<locals>.inner(ax, data, *args, **kwargs)
   1521 @functools.wraps(func)
   1522 def inner(ax, *args, data=None, **kwargs):
   1523     if data is None:
-> 1524         return func(
   1525             ax,
   1526             *map(cbook.sanitize_sequence, args),
   1527             **{k: cbook.sanitize_sequence(v) for k, v in kwargs.items()})
   1529     bound = new_sig.bind(ax, *args, **kwargs)
   1530     auto_label = (bound.arguments.get(label_namer)
   1531                   or bound.kwargs.get(label_namer))

File [~/NSBI-workflow-tutorial/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/matplotlib/axes/_axes.py:7531](https://jupyterhub.ssl-hep.org/user/[email protected]/research-softwa-dia-october2025-47hkxj8t/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/matplotlib/axes/_axes.py#line=7530), in Axes.hist2d(self, x, y, bins, range, density, weights, cmin, cmax, **kwargs)
   7528 if cmax is not None:
   7529     h[h > cmax] = None
-> 7531 pc = self.pcolormesh(xedges, yedges, h.T, **kwargs)
   7532 self.set_xlim(xedges[0], xedges[-1])
   7533 self.set_ylim(yedges[0], yedges[-1])

File [~/NSBI-workflow-tutorial/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/awkward/highlevel.py:1298](https://jupyterhub.ssl-hep.org/user/[email protected]/research-softwa-dia-october2025-47hkxj8t/.pixi/envs/nsbi-env-gpu/lib/python3.12/site-packages/awkward/highlevel.py#line=1297), in Array.__getattr__(self, where)
   1293         raise AttributeError(
   1294             f"while trying to get field {where!r}, an exception "
   1295             f"occurred:\n{type(err)}: {err!s}"
   1296         ) from err
   1297 else:
-> 1298     raise AttributeError(f"no field named {where!r}")

AttributeError: no field named 'T'

#1096 seems possibly related. Converting the flattened awkward arrays to numpy arrays is a workaround..

davidlange6 avatar Oct 28 '25 12:10 davidlange6

Hmm that's interesting.....ak.Array supports the __array__ protocol and I would hope that matplotlib would convert it to a np.ndarray first before doing anything with it. It looks like it's trying to transpose it as is before converting it to numpy....Maybe that's a request for matplotlib tbh. I don't know how transposition would look like in the general case for awkward arrays. If it's actually rectilinear sure...but I can't think of a general jagged transposition in the awkward array model.

ikrommyd avatar Oct 28 '25 13:10 ikrommyd