-
-
Notifications
You must be signed in to change notification settings - Fork 359
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
static array length should not change data interpretation #1886
Comments
I can definitely see where you're coming from here. It's a little at odds with Plots' core philosophy, though, to "attempt to figure out what you want it to do... not just what you tell it". A vector of 2- or 3- length StaticVectors is practically without exception a description of 2- or 3-dimensional point coordinates. This follows the behaviour for 2- and 3-length tuples (which is very widely used for generating plots). Arrays of 4+-element static arrays could be anything though - I doubt they are ever used in Plots' calls. Seen from Plots' perspective it would thus be least problematic to simply disallow plotting of 4+-element staticarrays, which would avoid the dispatch-on-length problem (though I thought the ability to dispatch on length was exactly a desirable property of StaticArrays?). Of course that would still collide with StaticArrays' desire to act like normal vectors. On the other hand it is possible that noone uses the ability to plot 2- or 3- length StaticArrays - it was originally implemented for FixedSizeArrays and just changed to StaticArrays in the julia-0.6 update - so we could try to scope the potential impact of doing what you suggest here and simply behave like they are normal vectors. Has this come up in actual use or is it just based on reviewing the code? |
IMO the main point is to specialize code on the length of StaticArrays. There might be some uses for dispatching on length, but it seems clear to me that you don't generally want functions doing arbitrarily different things for different lengths of array.
Just from reviewing the code. I think it's generally not good design to depend on other packages in order to treat their types differently than other similar types. There are who-knows-how-many julia array types out there, and plots can handle them all via general AbstractArray interfaces instead of by depending on them. But, as somebody who uses Plots from time to time, let's say I happen to have data in the form |
Yes, But, it's perfectly fine to use this same approach for all array types of course. I just have a hard time imagining when someone would have a Vector of length-2 SVectors and that would not be points, so it would just add an extra step. I see your point about explicitness, though I tend to think plotting code is a bit unusual in that it's almost invariably used interactively at the REPL, where flexibility and succinctness really help - especially as the ideomatic way to specify Plots' plots in library or reusable code is via recipes, which are 100% explicit. Anyway, I didn't get any big complains when I asked about changing the behaviour on Slack, so I'm open to changing it as you suggest. @daschw , do you agree? |
Sure, we don't need to use that exact name/syntax, just something to express that I have an iterable-of-iterables to treat as an array of points. It's a secondary request though of course. Thanks for considering this. |
Here's a PR implementing this: #1892 |
Sorry, I missed your question @mkborregaard. Yes I agree. |
Note: the PR that removes the StaticArrays dep does not change the time of |
That's your interpretation :P StaticArrays has come a long way since it replaced FixedSizeArrays - but this exact use case was a big motivation for writing FixedSizeArrays for me. I'm not sure if you can say "it was written as an optimization" generally implies that we can't use it to notify an API about user intentions. Of course the presence of As I see it, we would love to also check if an |
I essentially agree with @SimonDanisch . I really don't want Plots to breach the package ecosystem etiquette or some such thing, but as long as it's open to interpretation I think the syntax is useful here. |
To be honest, I agree with @JeffBezanson here:
I'd find it cleaner not to depend on StaticArrays. I think, as a general rule, Plots should implement type recipes for Base and stdlib types and type recipes for other packages should live in the respective package code or in an extra dedicated package like we did for Distributions etc. in StatPlots. However, I doubt that StaticArrays.jl would be willing to include a type recipe and a RecipesBase dependency and having a small extra Package like StaticArrayPlots.jl or similar would firstly probably not be used that much and secondly be weird in this situation because I guess it really depends on how much this interpretation that length 2 or 3 StaticArrays correspond to points is used in the wild. I never use it, but if there is some critical mass that relies on it and the StaticArrays dependency does not influence load or compilation time then the practical solution would probably be to keep the StaticArrays dependency. Otherwise, I'd prefer dropping it. |
How can we find the subset of published packages that relies directly (not transitively) on both RecipesBase and StaticArrays? That would be a good place to scope the use of this. |
I have no idea. |
|
Yes, I agree it would be better to treat all arrays of 2-vectors the same. Is the overhead really that bad? Does it matter, when you're plotting all the points anyway? I also just checked that
Fair point, but I still think this is a hack. Is there a standard 2d point type used by julia graphics packages? Or is |
I think we
I have no strong opinion on 1., but regarding 2. I think that it's the package's responsibility to define the visual interpretation of a type. Otherwise, where do we draw the line? Which packages should we depend on to make this decsion?
This would avoid the need to answer 1. here, but in the context of 2., this would just be a shift from a StaticArrays.jl dependency to a GeometryTypes.jl/Graphics.jl dependency. |
I agree --- generally a package defining However, that depends on how closely related the package is to graphics/visualization. For example, you might want to visualize a sorting algorithm, but doing that is pretty far from the typical applications of sorting itself, and so would probably be done by a separate package. It also depends on whether the type has a natural visual or geometric interpretation. It's so obvious how to geometrically interpret a
It makes sense to me that a graphics package would depend on one of those though, particularly if the Point types defined there are considered canonical. But if |
Fair point. In my opinion it would still be preferable if GeometryTpes would tell Plots how to interpret |
I'm fine with that. It could be even simpler for something as simple as a point though. My hope was that some package like Graphics.jl or GeometryTypes.jl would define just a few basic things like |
Yeah I guess that could work... We also discussed to have something like that in StaticArrays... |
Yes, I think depending on GeometryTypes in Plots would be the wrong way around - it's much better to have the package defining the type also define the plotting functionality. In this case that would involve GeometryTypes taking on a dep on the very small RecipesBase (300 lines of code with no exports and no dependencies that only changes along with julia minor versions), and then the line using RecipesBase
@recipe f(pts::AbstractVector{T}) where {T <: Union{Point{2}, Point{3}}} = [p.data for p in pts] in GeometryTypes would be sufficient to do using Plots, GeometryTypes
pts = rand(Point{2}, 100)
scatter(pts) with no dependencies between them - magic :-) In the context of using GeometryTypes for this, I guess an unclarity of semantics is whether While I sympathise with the principle, In the end, while I think it's a nice functionality to let go I'll defer to the decision of Daniel and Simon and have more or less already made the PRs to make the change happen. |
@JeffBezanson wrote
@SimonDanisch wrote
For the record, my interpretation is the same as Jeff's 😛 While StaticArrays began as simple rewrite of FixedSizeArrays to target a newer Julia compiler, I was philosophically committed to these being just My interpretation of dispatch (and the fact that In cases like this I find the rule I have been applying is: a generic function needs to be clear if a slot represents a single thing or a list of things. E.g. we have separate That all said, @SimonDanisch I do regret the gap between what StaticArrays is now and the convenience FixedSizeArrays provided for basic geometry in the past |
I've come around to thinking that the resolution here is to have Plots depend on GeometryTypes and have first-class support for Point, LineSegment and Polygon. Dependency-wise it adds nothing more than StaticArrays anyway and it makes sense to use these abstractions throughout Julia. @daschw how do you feel about this solution? It changes our normal philosophy for packages in the case of GeometryTypes but comes with advantages too for packages that use them (and for this case). |
replace StaticArrays with GeometryTypes (fix #1886)
Currently, plotting an array of 2-element StaticVectors treats the elements as 2d points. 3-element StaticVectors are treated as 3d points. Arrays of 4+-element static arrays, or other types of arrays, are instead treated as multiple line plots.
I believe the purpose of StaticArrays is to specialize code and data representation for a certain size, not to change semantics. For example
SVector{2}([1,2]) == [1,2]
is true; the objects are supposed to "mean" the same thing.I know this would be a (possibly major) breaking change, but I think it would make the API and mental model much cleaner. An extra small motivation is that ideally Plots should not depend on StaticArrays, since I don't believe it truly needs them (e.g. for performance). I don't know what the impact would be on load time and compile time, but removing dependencies can only help.
The text was updated successfully, but these errors were encountered: