Skip to content

allow using categorical data for color, marker, size, … #6214

Open

Description

@flying-sheep

currently specifying an array for color or size, only works for continuous data. using markers and colors mapped to subsets based on categorical data is hard and manual (basically you subset the data in a loop and call plot multiple times).

i thought it would be hard as list-of-string already means something for some parameters (markers and colors can be specified as strings). but there is pandas’ category dtype.

i propose that using a categorical vector for one of these parameters should be automatically mapped to a palette of colors/markers when specified as c or marker.

# with A, B, C, being either categorical or quantitative,
# S being quantitative, and M being categorical
plt.scatter('A', 'B', s='S', c='C', marker='M', data=df)

# of course also works with arrays, and bool acts like categorical data:
plt.scatter(arr[:,0], arr[:,1], c=arr[:,-1] > 0)

more palettes than just the colormap

the color palette for categorical data would be plt.rcParams['axes.prop_cycle'].by_key()['color'], the marker palette a new rcParam (maybe?)

those palettes would be cycled if there are too many categories.

legends

  • categorical: legend
  • discrete: (ordered legend or segmented bar)
  • continuous: bar (colorbar for color, isosceles trapezoid for size)

open questions

  • are integers treated as quantitiative + discrete (legend containing all separate values) or continuous (bar)
  • how to specify if a legend/colorbar/sizebar should created? it makes sense to automatically do it if we use the data= interface

Activity

  1. flying-sheep commented on Mar 23, 2016

    @flying-sheep
    Author

    @WeatherGod said:

    I am not sure what you mean by "this ship has sailed". All we implemented was a generic way to access data within a dataframe or other similar objects, and a minimal usage. I don't see any limitations to extending the syntax, but that'll have to be done judiciously, like how this first round of the API was done. There are a few technical improvements that will be needed (having multiple norms, be able to modify more properties, etc), but we have been wanting to implement them for awhile now.

  2. flying-sheep commented on Mar 23, 2016

    @flying-sheep
    Author

    well, see the open questions and the fact that allowing to use scatter(marker='ColName', data=...) is a breaking change since the column could be named e.g. 'o'…

  3. WeatherGod commented on Mar 23, 2016

    @WeatherGod
    Member

    Yes, in the face of ambiguity, we resist the temptation to guess. However,
    that doesn't mean that the problem can't be solved somehow (flags? other
    annotated types? etc.) We are open to solutions to these very real
    problems. We just don't want to slap together a haphazard solution that we
    would be stuck with and regret later.

    We just need someone to have an inspired idea on how to solve it.

    On Wed, Mar 23, 2016 at 12:44 PM, Philipp A. [email protected]
    wrote:

    well, see the open questions and the fact that allowing to use scatter(marker='ColName',
    data=...) is a breaking change since the column could be named 'o'…

    —
    You are receiving this because you were mentioned.
    Reply to this email directly or view it on GitHub
    #6214 (comment)

  4. tacaswell commented on Mar 23, 2016

    @tacaswell
    Member

    We also have a solicitation up for a GSoC student to work on categorical data.

    Plotting methods in mpl should never create a color bar or legend, those are (by design) separate steps.

    You can pass in a BoundryNorm for the color mapping which will give discrete colors (and the color bar code will show them as solid chunks).

    Looping over a groupby does not seem that onerous. It also gives you the flexbility to do any type of plotting in your loop (not just scatter, ex quiver, bar, etc). Thus instead of putting the logic in every plotting function, the user gets to own the complexity of their data reduction (which will always boil down to a numpy array) and then mpl will plot it.

    The core issue is that if you have a very restricted sort of data (tabular, many columns, lots of categorical) it may make sense to push many of the groupby and aggregation operations down into the plotting. This is my understanding of what people like about ggplot and is definitely the case with vegalite. When working on https://github.com/ellisonbg/altair the hardest part of translating their spec to be implemented on top of mpl was not the plotting, but sorting out the aggregations/computation aspect of it. Those complexities are what I think MPL should not pick up. One of the reasons for the wide ranging success of mpl is precisely that it stays out (to a large degree, hist and contour are major exceptions) of computation.

    As I said in the other thread we are very positive on domain specific charting libraries to be built on top of mpl, but the core team does not have the bandwidth (or domain knowledge in many cases) to write them.

  5. added this to the milestone on Mar 23, 2016
  6. added
    Difficulty: Hardhttps://matplotlib.org/devdocs/devel/contribute.html#good-first-issues
    on Mar 23, 2016
  7. flying-sheep commented on Mar 24, 2016

    @flying-sheep
    Author

    Thus instead of putting the logic in every plotting function

    refactoring the plotting functions to work more grammar-of-graphics-like would manage to do that as well.

    1. raw data and parameters as given to function
    2. mapping of dataframe-style representation of relevant data data to
      • one or more geometries (bar, scatter, image, …)
      • a set of aesthetics per geometry (colors, markers, size, …)
    3. representation of graphics

    currently i guess they skip step 2 and go directly from 1 to 3, leading to duplicate effort, am i right?

    the hardest part of translating their spec to be implemented on top of mpl was not the plotting, but sorting out the aggregations/computation aspect of it

    jup, i’m not an expert or even advanced there but i also don’t get why that shoud be part of plotting. if anything, plotting should reshape (melt/cast/pivot) the data, not do statistics on it.

    providing a specialized set of helpers to do those easily is beside the point

  8. story645 commented on Jul 18, 2016

    @story645
    Member

    @flying-sheep would a colormap dict work, at least partially. I'm thinking of something in the style of ListedColormap:

    cmap, norm = mcolors.DictColor({'snow':'gray', 'rain':'blue, 'broken detector':red})
    

    that would then be auto hooked into colorbars (and could possibly be hooked into legends via a legend_from_cmap helper...). My main qualm with it is that it would have to do both cmap and norm simultaneously, but mcolors handles both the cmap & norm code and everything that takes a cmap arg takes a norm arg, so that may not be much overhead.

  9. flying-sheep commented on Jul 18, 2016

    @flying-sheep
    Author

    sounds good!

  10. modified the milestones: , on Oct 3, 2017
  11. naught101 commented on Dec 7, 2017

    @naught101

    At the moment, I can run scatter([0,1,2], [0,1,2], c=[0,1,2]), which results in a nice plot, and I can run scatter([0,1,2], ['A','B','C'], c=[0,1,2]), which also results in a nice plot, with categories atomatically mapped to the y-axis.

    scatter([0,1,2], [0,1,2], c=['A','B','C']) doesn't work though. It would be really nice if it did, with each category automatically mapped to a colour. That would make things like these questions much easier to answer: https://stackoverflow.com/questions/26139423/plot-different-color-for-different-categorical-levels-using-matplotlib, https://stackoverflow.com/questions/31883097/elegant-way-to-match-a-string-to-a-random-color-matplotlib

    Not sure if that should be submitted as a separate issue or not.

  12. blalterman commented on Dec 7, 2017

    @blalterman
  13. story645 commented on Dec 7, 2017

    @story645
    Member

    @naught101 the thing that makes it difficult is the reason it's not implemented, namely that it would require extending unit support to all scalermappable objects (so functions like imshow and pcolor and anything else with a colorbar) and then hooking in a way to generate legends off of colormaps. It's definitely on my wishlist for categoricals, but on the backburner while we refine the current implementation.

  14. 8 remaining items

  15. mwaskom commented on Jun 16, 2018

    @mwaskom

    For the time being, you might want to have a look at seaborn for more specialized data science related plots.

    In fact this was recently added to seaborn and will be available in the next release: mwaskom/seaborn#1436

  16. modified the milestones: needs sorting, on Aug 11, 2019
  17. dburkhardt commented on Feb 6, 2020

    @dburkhardt

    I think this functionality has been added at some point.

    The following code works as intended:

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    
    data = np.random.normal(size=(100,2))
    colors = pd.Series(data[:,0], dtype='category')
    sizes = pd.Series(data[:,1], dtype='category')
    
    plt.scatter(data[:,0], data[:,1], c=colors, s=sizes)
  18. story645 commented on Feb 6, 2020

    @story645
    Member

    @dburkhardt that data is a float, which should have always worked barring some bugs on pandas series unpacking. Here categorical is used interchangeably with string data types and string datatypes still don't work.

  19. jklymak commented on Feb 6, 2020

    @jklymak
    Member

    ... note that Matlab put gscatter into a domain-specific toolbox.

  20. dburkhardt commented on Feb 6, 2020

    @dburkhardt

    Good point @jklymak, but that toolbox, Statistics and Machine Learning, is also where Mathworks put boxplots (https://www.mathworks.com/help/stats/boxplot.html) which are provided in matplotlib (https://matplotlib.org/api/_as_gen/matplotlib.pyplot.boxplot.html).

    Either way, I also would make use of this functionality if it did make it's way into matplotlib, but unfortunately my programming skills are not strong enough for me to be confident in implementing it so I can't do much more than +1 the topic.

  21. jklymak commented on Feb 6, 2020

    @jklymak
    Member

    There is a cost-benefit to this sort of thing. It looks like seaborn has this, which is a more stats-oriented package than matplotlib, so having them maintain it is great. If I were doing this, I'd just do something like the following, which is hardly more work than the proposed interface:

    categories =['A', 'B', 'C']
    colors=['r', 'g', 'b']
    symb = ['d', 's', 'o']
    
    for ind, cat in enumerate(categories):
        in = np.where(data.cat==cat)
       ax.scatter(data.x[in], data.y[in], c=colors[ind], markerstyle=symb[ind])
  22. modified the milestones: , needs sorting on Oct 6, 2022
  23. github-actions commented on Oct 9, 2023

    @github-actions

    This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

  24. added
    keepItems to be ignored by the “Stale” Github Action
    and removed
    status: inactiveMarked by the “Stale” Github Action
    on Oct 9, 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

    Difficulty: Hardhttps://matplotlib.org/devdocs/devel/contribute.html#good-first-issuesNew featurekeepItems to be ignored by the “Stale” Github Actiontopic: categorical

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions