Skip to content

[ENH]: Make it so that linestyle works the same way as color when plotting several bars, lines, scatter points, etc. #23222

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

Closed
AndreasBugten opened this issue Jun 8, 2022 · 3 comments

Comments

@AndreasBugten
Copy link

AndreasBugten commented Jun 8, 2022

Problem

Hello!

I am trying to plot a series of bars within a bar plot, and I want each bar to have its own color and linestyle. I intend to achieve this by using a list of colors, and a list of linestyles, and then simply plot the bars and set the color and linestyle to their respective lists. This works for color, but not for linestyle, since the linestyle function does not recognize a list as input.

Below I have two code snippets, and their respective outputs, which highlights the problem.

First, without using linestyle:
image

Then, using linestyle:
image

I have checked that all of the linestyles are compatible with the plt.bar function.

Proposed solution

No response

@oscargus
Copy link
Member

oscargus commented Jun 8, 2022

Some parameters are dealt with here and a cycler is created which is used to loop over for each rectangle patch:

linewidth = itertools.cycle(np.atleast_1d(linewidth))
hatch = itertools.cycle(np.atleast_1d(hatch))
color = itertools.chain(itertools.cycle(mcolors.to_rgba_array(color)),
# Fallback if color == "none".
itertools.repeat('none'))
if edgecolor is None:
edgecolor = itertools.repeat(None)
else:
edgecolor = itertools.chain(
itertools.cycle(mcolors.to_rgba_array(edgecolor)),
# Fallback if edgecolor == "none".
itertools.repeat('none'))

The remaining parameters are added to the rectangle patch here:

r._internal_update(kwargs)

I see two possible solutions:

  1. Create a cycler for the linestyles/dashpatterns.
  2. Add the remaining parameters to the BarCollection instead. (Not sure this works though.) It is a BarContainer, not a BarCollection.

I'll take this into consideration in #23056 and see if something can be done to make simplify this procedure.

@timhoffm
Copy link
Member

timhoffm commented Jun 8, 2022

I think it has been a design mistake that bar() can style individual bars separately. Conceptually, all bars from one call belong to one logical data set (which has multiple values). For example, one can only set one label.

Therefore I suggest not to expand further in this direction. We generally don't want trivial vectorization on the methods as that increases implementation complexity.

for x, y, color, linestyle in zip([1, 1.25, 1.5, 1.75], [2, 2, 2, 2], colors, linestyles):
    ax.bar(x, y, 0.05, color=color, linestyle=linestyle)

seems simple enough.

@timhoffm
Copy link
Member

timhoffm commented Jul 6, 2022

@AndreasBugten thanks for the suggestion. As laid out in the comment above, I don't want to expand the bar() API to style individual bars separately.

@timhoffm timhoffm closed this as completed Jul 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants