Skip to content

[ENH] Initial support for linestyle cycling on plot() #3818

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
wants to merge 1 commit into from

Conversation

WeatherGod
Copy link
Member

Work in progress. Need tests and need to make sure I don't have unintended side effects.

Do we want to do markers as well? Possibly hatches, too?

@@ -269,6 +269,10 @@ backend : %(backend)s
# as list of string colorspecs:
# single letter, long name, or
# web-style hex
#axes.linestyle_cycle: - # linestyle cycle for plot lines as a list
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be a list

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just add a comma there?

@tacaswell
Copy link
Member

I find the _process_plot_var_args to be needlessly complicated. The parsing functions should probably go into cbook and the state buried in this class split out and hung off of the Axes object, but that is probably a bigger re-factor than is called for in this PR.

@tacaswell
Copy link
Member

There is the generalization to have a 'style_cycle` which is loaded with dicts so you can set up what ever crazy cycles you want (all the colors with 'x', all the colors with 'o',,, vs colors + markers in lockstep vs 'b' with all the symbols, 'r' with all the symbols...).

@WeatherGod
Copy link
Member Author

yeah, the process_plot_var_args was my original hangup in solving this problem. I have made about 4 separate attempts at solving it, and each time I failed to fix it. In retrospect, I think I kept trying to solve too much at once rather than incrementally chipping away at it.

As for your generalization, I am not exactly sure how a dictionary would enable that. One could supply iterators generated from itertools.product() to each cycle-setter, couldn't they?

@tacaswell
Copy link
Member

style_cyle = [{'linestyle: '-', 'color':'b', 'marker':x}, {'linestyle': '-', 'color':'r', 'marker':'o'}...]

itertools.product returns a single iterator over the tuples, I am not sure how to split that up into the N inerators (wrapped in cycle?) you would need to assign to each cycle property.

@WeatherGod
Copy link
Member Author

Ah, you are right about product(); I wasn't thinking it through. The difficulty with your proposal is controlling which sets get used where. Right now, there are, internally, two color cycles, one for plot() and one for bar(). I doubt one would want the linestyle cycle to apply to bar()-based calls.

Then there is the ugly question of compatibility. How would style_cycle and axes.color_cycle coexist?

@WeatherGod
Copy link
Member Author

Note to self, just because tests.py --pep8 returns OK in about 2 seconds doesn't mean that PEP8 tests were actually done (my anaconda environment didn't have pep8 installed...)

Added nominal tests for color and linestyle cycles
@pelson
Copy link
Member

pelson commented Dec 3, 2014

So I was just reviewing some code and came up with an idea for color cycling which may have some mileage (in fact, it is just a reincarnation of the idea @tacaswell was proposing above).

Right now, we have a special meaning for the keyword value None, to go and look up the color from the rcParams. What if we had a StyleCycle class which allowed us to cycle over a style definition (not just a dictionary). The style definition should be given a created artist, and it should be responsible for changing its appearance.

A dumb implementation might look like:

class StyleDefinitionBase(object):
    def update_artists(self, artists):
         """Update the given artists to this style."""

class ColorCycleStyle(StyleDefinitionBase):
    def __init__(self, colors):
        self.colors = itertools.cycle(colors)

    def update_artists(self, aritists):
        next_color = next(self.colors)
        for artist in artists:
             artist.set_color(next_color)

I propose that a standard plotting keyword be added, something like style_cycle, which allows users to setup their own cycling. The code might even be simplified at https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes/_base.py#L236 as a result of doing this.

@WeatherGod
Copy link
Member Author

I once tried something like that a long time ago, but failed. The failure
was partly due to my inexperience with python at the time and my failure to
really understand matplotlib like I do now. Logically, it is sound.
Although, I originally envisioned a different approach: have Style objects
that could be cycled rather than a single object with cyclable parameters.
This is before I even knew about graphics contexts. One thing that is nice
with a StyleCycle is that the cycling is contained, and so plotting code do
not need to know much about it to get its benefit.

Perhaps this idea needs to dovetail with some of the artist property/css
styling MEPs?

On Wed, Dec 3, 2014 at 12:49 PM, Phil Elson notifications@github.com
wrote:

So I was just reviewing some code and came up with an idea for color
cycling which may have some mileage (in fact, it is just a reincarnation of
the idea @tacaswell https://github.com/tacaswell was proposing above).

Right now, we have a special meaning for the keyword value None, to go
and look up the color from the rcParams. What if we had a StyleCycle
class which allowed us to cycle over a style definition (not just a
dictionary). The style definition should be given a created artist, and it
should be responsible for changing its appearance.

A dumb implementation might look like:

class StyleDefinitionBase(object):
def update_artists(self, artists):
"""Update the given artists to this style."""

class ColorCycleStyle(StyleDefinitionBase):
def init(self, colors):
self.colors = itertools.cycle(colors)

def update_artists(self, aritists):
    next_color = next(self.colors)
    for artist in artists:
         artist.set_color(next_color)

I propose that a standard plotting keyword be added, something like
style_cycle, which allows users to setup their own cycling. The code
might even be simplified at
https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/axes/_base.py#L236
as a result of doing this.


Reply to this email directly or view it on GitHub
#3818 (comment)
.

@tacaswell tacaswell modified the milestones: proposed next point release, next point release Feb 19, 2015
@tacaswell
Copy link
Member

@WeatherGod I think this should be re-address using Cycler.

@tacaswell tacaswell modified the milestones: proposed next point release, next point release Jun 17, 2015
@WeatherGod
Copy link
Member Author

Right, it does look like the right thing to do. So basically, redo this to use the Cycler objects?

@tacaswell
Copy link
Member

Yes. I think the right path here is to add a Cycler object (well a itertools.cycle of a Cycler) to the Axes, everyplace we use the color cycle internally change to look at deal with dicts out of Cycler, deprecate the current color cycle, but fake it up well enough that user code that uses it still works, and add the needed rcparams + helper functions.

@WeatherGod
Copy link
Member Author

Sounds like a good project to do on an airplane ride to SciPy, don't you
think? ;-)

On Wed, Jun 17, 2015 at 9:56 AM, Thomas A Caswell notifications@github.com
wrote:

Yes. I think the right path here is to add a Cycler object (well a
itertools.cycle of a Cycler) to the Axes, everyplace we use the color
cycle internally change to look at deal with dicts out of Cycler,
deprecate the current color cycle, but fake it up well enough that user
code that uses it still works, and add the needed rcparams + helper
functions.


Reply to this email directly or view it on GitHub
#3818 (comment)
.

@pelson
Copy link
Member

pelson commented Jun 22, 2015

Sounds like a good project to do on an airplane ride to SciPy, don't you think? ;-)

👍 - that, or in the sprints proper... might even be a nice little project for somebody with less experience.

@ppinard
Copy link
Contributor

ppinard commented Jul 30, 2015

The "default changes" tag should be added to this pull request.

@tacaswell
Copy link
Member

This should not be changing any defaults, just adding more flexibility.

On Thu, Jul 30, 2015, 7:26 AM Philippe Pinard notifications@github.com
wrote:

The "default changes" tag should be added to this pull request.


Reply to this email directly or view it on GitHub
#3818 (comment)
.

@tacaswell
Copy link
Member

Sorry, was confused what pr this was my email

@WeatherGod
Copy link
Member Author

This should be considered as superseded by #4686.

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

Successfully merging this pull request may close these issues.

4 participants