Skip to content

Rotate markers in Scatter plot #2478

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 7 commits into from
Closed

Conversation

mgoacolou
Copy link
Contributor

This a re-summit of the #2432

Make possible to give a scalar or an array for rotate markers. This is usefull for representing for example Speed, Type, Direction of mobile targets.

if self._sizes.size > self._angles.size:
self._angles = np.ma.resize(self._angles, self._sizes.shape)
else:
self._sizes = np.ma.resize(self._sizes, self._angles.shape)
Copy link
Member

Choose a reason for hiding this comment

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

This is different from the behavior of other collection parameters that "wrap around" -- that is, for a given symbol N, the angle would be angles[N % len(angles)].

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is what exactly do np.ma.resize

Copy link
Member

Choose a reason for hiding this comment

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

I don't think it's the same. Here's the current behavior. Say you have 3 sizes (A, B, C) and 2 colors (X, Y), then you get the following combinations:

(A, X)
(B, Y)
(C, X)

I think with the above, you would only get the minimum number of either the sizes or angles.

That said, I think to get this behavior, and be consistent with the other properties, you'll have to extend the backends to understand angles.

@@ -3138,7 +3138,7 @@ def dopatch(xs, ys):
medians=medians, fliers=fliers)

@docstring.dedent_interpd
def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None,
def scatter(self, x, y, s=20, c='b', marker='o', angles=0, cmap=None, norm=None,
Copy link
Member

Choose a reason for hiding this comment

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

The new kwarg should be at the end to preserve reverse compatibility.

@tacaswell
Copy link
Member

You should not merge master into your working branch, but re-base your branch onto current master. Please remove the merge commit and rebase your commit.

@tacaswell
Copy link
Member

This needs another rebase and to have a few remaining comments addressed.

@tacaswell tacaswell modified the milestones: v1.5.x, v1.4.0 Feb 25, 2014
@tacaswell
Copy link
Member

@mgoacolou I have re-milestoned this as 1.5.x as this needs a re-base and we have not heard from you in a few months. If you can get this re-based and fixed up in the near future we can get it in to 1.4.0.

@mgoacolou
Copy link
Contributor Author

I'm testing my rebase

@tacaswell tacaswell modified the milestones: v1.4.0, v1.5.x Feb 25, 2014
@@ -3469,6 +3472,7 @@ def scatter(self, x, y, s=20, c='b', marker='o', cmap=None, norm=None,
raise ValueError("x and y must be the same size")

s = np.ma.ravel(s) # This doesn't have to match x, y in size.
angles = np.ma.ravel(angles) # This doesn't have to match x, y in size.
Copy link
Member

Choose a reason for hiding this comment

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

This is one character too long for pep8.

@tacaswell
Copy link
Member

one of the image tests seems to be consistently failing

======================================================================

FAIL: matplotlib.tests.test_transforms.test_pre_transform_plotting.test

----------------------------------------------------------------------

Traceback (most recent call last):

File "/home/travis/virtualenv/python2.7/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest

self.test(*self.arg)

File "/home/travis/virtualenv/python2.7/local/lib/python2.7/site-packages/matplotlib-1.4.x-py2.7-linux-x86_64.egg/matplotlib/testing/decorators.py", line 50, in failer

result = f(*args, **kwargs)

File "/home/travis/virtualenv/python2.7/local/lib/python2.7/site-packages/matplotlib-1.4.x-py2.7-linux-x86_64.egg/matplotlib/testing/decorators.py", line 201, in do_test

'(RMS %(rms).3f)'%err)

ImageComparisonFailure: images not close: /home/travis/build/matplotlib/tmp_test_dir/result_images/test_transforms/pre_transform_data.png vs. /home/travis/build/matplotlib/tmp_test_dir/result_images/test_transforms/pre_transform_data-expected.png (RMS 20.345)

@mgoacolou
Copy link
Contributor Author

I corrected the bug in computation of scale. The figure (expected and generated) are close but have not the same x/y limites. Is there a way to know why?

@@ -709,32 +709,121 @@ class _CollectionWithSizes(Collection):
"""
Base class for collections that have an array of sizes.
"""
def __init__(self):
Copy link
Member

Choose a reason for hiding this comment

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

This is a major change as sub-class are not guaranteed to call Collections.__init__ because it used to be a no-op (the default) function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

super() guarantees the call of all init and only once if they exists

@tacaswell tacaswell modified the milestones: v1.5.x, v1.4.0 Apr 4, 2014
@tacaswell tacaswell modified the milestones: proposed next point release, next point release Feb 19, 2015
@tacaswell tacaswell modified the milestones: proposed next point release, next point release Jun 22, 2015
@tacaswell
Copy link
Member

@mgoacolou any interest in continuing to work on this?

RegularPolyCollection already has a rotation param. Probably should be consistent with that naming.

@mgoacolou
Copy link
Contributor Author

@tacaswell Hi, I am now more confident with git now. I'll take a look this week on this.

@flying-sheep
Copy link

oh nice, definitely looking forward to this?

so am i correct that after this is in, i can e.g. do:

df = pd.DataFrame({X: ..., Y: ..., C: ['Foo', 'Bar', ...]})
marker_map = {'Foo': 'o', 'Bar': 'x'}

plot(df.X, df.Y, marker=[marker_map[c] for c in df.C])

@tacaswell
Copy link
Member

No, this is the other meaning of rotate as in 'change the orientation of the marker'. Basically quiver, but with any marker not just arrows.

There are deep performance related issue that plot has exactly one marker. I would do what you want as

for k, _df in df.group_by('C'):
    ax.plot(_df,X, _df.Y, **style_map[k])

@flying-sheep
Copy link

is there a more ggplot-like interface to matplotlib? i.e. where you give a DataFrame and column names to x, y, marker, c, and so on and it does _the right thing_™ (including legends)?

seaborn just has its own high-level plots, and pandas’ DataFrame.plot only allows specifying x and y in this way.

i basically want to do: scatter('Height', 'Weight', c='Age', marker='Gender'), and it uses the color cycle for categorical variables and the colormap for continuous ones, plots legend(s) and colorbar(s) and presto!

@WeatherGod
Copy link
Member

We are working towards supporting a more robust API like that. You can get
partly there right now by passing the dataframe as the "data" argument and
use the string names for the x and y arguments. I don't think we support
the color and marker arguments yet, though.

On Wed, Mar 23, 2016 at 10:10 AM, Philipp A. notifications@github.com
wrote:

is there a more ggplot-like interface to matplotlib? i.e. where you give a
DataFram and column names to x, y, marker, c, and so on and it does _the
right thing_™ (including legends)?

seaborn just has its own high-level plots, and pandas’ DataFrame.plot only
allows specifying x and y in this way.

i basically want to do: scatter('Height', 'Weight', c='Age',
marker='Gender'), and it uses the color cycle for categorical variables
and the colormap for continuous ones.


You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub
#2478 (comment)

@flying-sheep
Copy link

currently, mpl works on a “series-based” level, which imho makes no sense for multidimensional data: you can have one dimension represented by shape, the other by color, the third by size, and two more by x/y position. this results in an exponential number of series.

therefore to make sense, your API must deviate from the previous model, and simply track 1. each point individually and 2. each represented feature via legend (marker shape, discrete color), colorbar (continuous color), “volume slider triangle” or axis label (x/y position).

like this, but using an isosceles trapezoid as “colorbar for size”:

@tacaswell
Copy link
Member

color and size should work with scatter + data, but not marker.

The pandas/table/dataframe/R view of data is not universal or fundamental where as vectors / arrays of number are, hence that is what the core of mpl targets and will continue to target.

There is definitely interest from many parties for there to a pandas-aware domain-specific plotting library that lives under the matplotlib gh umbrella organization that can require pandas and do these 'magic' things. The only hold up is developer time. @flying-sheep You have any interest in leading this effort?

That said, scatter creates a PathCollection and it should be pretty easy to extend it to take a vector of shapes instead of broadcasting a single shape.

@flying-sheep
Copy link

i don’t know if i’m suited, but i’d definitely like to chime in wherever discussion is happening regarding the data= API. (where does it happen? could you give me a link?)

regarding an universal interface, i disagree: the grammar of graphics is a deconstruction/analysis of the way data visualization happens. and those rules do directly translate into a data frame structure: a heterogeneous collection of feature columns that each carry one entry for each sample.

by mapping those feature columns onto graphical features, we get all possible permutations of visualizations. so basically, we have to (implicitly or explicitly) reshape our data into this structure anyway when visualizing it, so we might as well use an interface optimized for this shape (pandas.DataFrame)

@tacaswell
Copy link
Member

The data kwarg API shipped with v1.5.0.

@flying-sheep
Copy link

ah, OK, so this ship has sailed then. damn.

i submitted #6214 for further discussion

@WeatherGod
Copy link
Member

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.

On Wed, Mar 23, 2016 at 12:27 PM, Philipp A. notifications@github.com
wrote:

ah, OK, so this ship has sailed then. damn.

i submitted #6214 #6214
for further discussion


You are receiving this because you commented.
Reply to this email directly or view it on GitHub
#2478 (comment)

@tacaswell tacaswell modified the milestones: 2.2 (next next feature release), 2.1 (next point release) Aug 13, 2017
@jklymak
Copy link
Member

jklymak commented Oct 5, 2018

... I'm going to close this as abandoned. I'm also not aware that anyone has asked for this functionality for quite a while, and while it looks cool its a significant complication to the code... Feel free to re-open or ask to have it re-opened if I'm closing in error.

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

Successfully merging this pull request may close these issues.

7 participants