FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

[ENH]: Multi hatching in `ax.stackplot()` · Issue #27146 · matplotlib/matplotlib · GitHub

Repository navigation

[ENH]: Multi hatching in ax.stackplot() #27146

Closed

Description

Problem

ax.stackplot() is used for conveniently plotting stacked area plot.

The documentation says that any **kwargs is passed on to ax.fill_between.

So, it all works fine if I work with colours, but not so much with hatching pattern.

If I want to add hatching, this is what I get by default:

import matplotlib.pyplot as plt
import numpy as np

# Data
cols = 10
rows = 4

data = (
    np.reshape(np.arange(0, cols, 1), (1, -1)) ** 2
    + np.reshape(np.arange(0, rows), (-1, 1))
    + np.random.random((rows, cols))*5
)

# Plot
fig, ax = plt.subplots(
    figsize=(10,6),
    facecolor="white",
    layout="constrained"
)
fig.suptitle(
    "with hatching",
    fontsize=25,
    weight="bold"
)

x = range(data.shape[1])
ax.stackplot(
    x, data,
    hatch="x"
)

ax.set_xlim(0, 9)
ax.set_ylim(0, 350)

The outcome:

But I would be more interested in getting something like this:

Proposed solution

The calling signature would be the same as before with exception that the hatch parameter would accept e.g. a list with hatching styles you want to use.

Example:

ax.stackplot(
    x, data,
    hatch=["x", "\\", ".", "-"]
)

The example I've used above in the problem was create using the code below and in this case it varies the hatching by the density:

fig, ax = plt.subplots(
    figsize=(10,6),
    facecolor="white",
    layout="constrained"
)
fig.suptitle(
    "with individual hatching",
    fontsize=25,
    weight="bold"
)

x = range(data.shape[1])
stack_baseline = np.zeros((data.shape[1]))
for i, y in enumerate(data):
    ax.fill_between(
        x, stack_baseline, y+stack_baseline,
        facecolor=(1, 1, 1, 0),
        hatch="x"*(data.shape[0]-i)
    )
    stack_baseline += y

ax.set_xlim(0, 9)
ax.set_ylim(0, 350)

Activity

  1. KartikeyBartwal commented on Oct 20, 2023

    Hello!
    Don't you think 'with hatching' looks cleaner and makes it easier to extract insights? It's never a bad idea to have another style of representation at our disposal, but what is your opinion on this?

  2. rcomer commented on Oct 20, 2023

    Member

    To me this request seems analogous to the hatch parameter added to pie at v3.7.
    https://matplotlib.org/stable/users/prev_whats_new/whats_new_3.7.0.html#hatch-parameter-for-pie

  3. added
    🌱 Good first issueOpen a pull request against these issues if there are no active ones!
    on Oct 20, 2023
  4. github-actions commented on Oct 20, 2023

    Good first issue - notes for new contributors

    This issue is suited to new contributors because it does not require understanding of the Matplotlib internals. To get started, please see our contributing guide.

    We do not assign issues. Check the Development section in the sidebar for linked pull requests (PRs). If there are none, feel free to start working on it. If there is an open PR, please collaborate on the work by reviewing it rather than duplicating it in a competing PR.

    If something is unclear, please reach out on any of our communication channels.

  5. timhoffm commented on Oct 20, 2023

    Member

    This is a reaonable request.

    It's a good first issue because the change is local in

    def stackplot(axes, x, *args,
    labels=(), colors=None, baseline='zero',
    **kwargs):
    """
    Draw a stacked area plot.
    Parameters
    ----------
    x : (N,) array-like
    y : (M, N) array-like
    The data is assumed to be unstacked. Each of the following
    calls is legal::
    stackplot(x, y) # where y has shape (M, N)
    stackplot(x, y1, y2, y3) # where y1, y2, y3, y4 have length N
    baseline : {'zero', 'sym', 'wiggle', 'weighted_wiggle'}
    Method used to calculate the baseline:
    - ``'zero'``: Constant zero baseline, i.e. a simple stacked plot.
    - ``'sym'``: Symmetric around zero and is sometimes called
    'ThemeRiver'.
    - ``'wiggle'``: Minimizes the sum of the squared slopes.
    - ``'weighted_wiggle'``: Does the same but weights to account for
    size of each layer. It is also called 'Streamgraph'-layout. More
    details can be found at http://leebyron.com/streamgraph/.
    labels : list of str, optional
    A sequence of labels to assign to each data series. If unspecified,
    then no labels will be applied to artists.
    colors : list of color, optional
    A sequence of colors to be cycled through and used to color the stacked
    areas. The sequence need not be exactly the same length as the number
    of provided *y*, in which case the colors will repeat from the
    beginning.
    If not specified, the colors from the Axes property cycle will be used.
    data : indexable object, optional
    DATA_PARAMETER_PLACEHOLDER
    **kwargs
    All other keyword arguments are passed to `.Axes.fill_between`.
    Returns
    -------
    list of `.PolyCollection`
    A list of `.PolyCollection` instances, one for each element in the
    stacked area plot.
    """
    y = np.vstack(args)
    labels = iter(labels)
    if colors is not None:
    colors = itertools.cycle(colors)
    else:
    colors = (axes._get_lines.get_next_color() for _ in y)
    # Assume data passed has not been 'stacked', so stack it here.
    # We'll need a float buffer for the upcoming calculations.
    stack = np.cumsum(y, axis=0, dtype=np.promote_types(y.dtype, np.float32))
    _api.check_in_list(['zero', 'sym', 'wiggle', 'weighted_wiggle'],
    baseline=baseline)
    if baseline == 'zero':
    first_line = 0.
    elif baseline == 'sym':
    first_line = -np.sum(y, 0) * 0.5
    stack += first_line[None, :]
    elif baseline == 'wiggle':
    m = y.shape[0]
    first_line = (y * (m - 0.5 - np.arange(m)[:, None])).sum(0)
    first_line /= -m
    stack += first_line
    elif baseline == 'weighted_wiggle':
    total = np.sum(y, 0)
    # multiply by 1/total (or zero) to avoid infinities in the division:
    inv_total = np.zeros_like(total)
    mask = total > 0
    inv_total[mask] = 1.0 / total[mask]
    increase = np.hstack((y[:, 0:1], np.diff(y)))
    below_size = total - stack
    below_size += 0.5 * y
    move_up = below_size * inv_total
    move_up[:, 0] = 0.5
    center = (move_up - 0.5) * increase
    center = np.cumsum(center.sum(0))
    first_line = center - 0.5 * total
    stack += first_line
    # Color between x = 0 and the first array.
    coll = axes.fill_between(x, first_line, stack[0, :],
    facecolor=next(colors), label=next(labels, None),
    **kwargs)
    coll.sticky_edges.y[:] = [0]
    r = [coll]
    # Color between array i-1 and array i
    for i in range(len(y) - 1):
    r.append(axes.fill_between(x, stack[i, :], stack[i + 1, :],
    facecolor=next(colors),
    label=next(labels, None),
    **kwargs))
    return r

    and you can simply handle hatching analogous to the existing color handling.

  6. pawjast commented on Oct 20, 2023

    Author

    Hello! Don't you think 'with hatching' looks cleaner and makes it easier to extract insights? It's never a bad idea to have another style of representation at our disposal, but what is your opinion on this?

    To me, uniform hatching covering the whole data area is purely decorative and you still need colours to understand the data. As oppose to when you have individual hatching styles. Then you can go only with the hatching fill and remove the colours. Scientific papers are often required to be made in a way so you can print them in black and white. And they often use hatching for this purpose to distinguish between different areas.

  7. nbarlowATI commented on Oct 20, 2023

    Contributor

    Hi! I agree on the usefulness of having different hatching styles in a stack plot, and had a go at implementing this following the guidance above (many thanks for making this so clear and newbie-friendly BTW!) in the draft PR: #27158

  8. added this to the v3.9.0 milestone on Oct 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    New feature🌱 Good first issueOpen a pull request against these issues if there are no active ones!

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL