Skip to content
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

How to draw a single path with different coloring on different segments? #705

Closed
zywind opened this issue Sep 24, 2015 · 14 comments
Closed

Comments

@zywind
Copy link

zywind commented Sep 24, 2015

Is there a way to do this? The current behavior is that whenever you set color, the lines are connected based on the color group. I would like to connect the lines based on the order in which the data appears, but coloring the segments based on another variable.

@tbreloff
Copy link
Contributor

Related to this, I'd like the ability to change other properties of individual line segments as well, such as width or line_style. It's certainly possible within Compose... what would it take to open this up to Gadfly.Geom as well? (I'm happy to submit a PR if you can point me in the right direction)

@timholy
Copy link
Collaborator

timholy commented Sep 24, 2015

You can change them post-hoc in Immerse with setproperties!. See https://github.com/JuliaGraphics/Immerse.jl/blob/master/test/properties.jl

That doesn't directly address the original question, however.

@tbreloff
Copy link
Contributor

I spent some time inside Gadfly and Compose looking into this, and I think this is going to be tricky without a big rewrite of some core parts of both packages. Sorry to say, no matter how much time I spend staring at those internals, they are never as intuitive as I want them to be.

It seems that around here the properties (stroke color, for example) are pushed onto the stack before the loop drawing all the children. This means that all children get the same properties, even if you pass an array of colors into the stroke method within Compose. In fact, there's a place with a hardcoded 1-index in which I think guarantees that it won't access the color vector when setting cairo properties.

@dcjones please correct me if I'm wrong about any of this!

@dcjones
Copy link
Collaborator

dcjones commented Sep 25, 2015

@zywind There's not a built in way to do per-segment coloring per se, but you can fake it without too much effort by just making a separate line for each segment. Here's an example:
screen shot 2015-09-24 at 11 57 10 pm

@tbreloff The hard-coded 1-index is applying scalar properties, for which there only is one element, so it's not discarding properties. If you want to draw line segments differently, you just have to split them into separate lines. That's how it works on most graphics backends (cairo, svg, etc), compose isn't peculiar in this regard. So coloring segments differently could just be implemented in Geom.line rather easily, by just automating what I did above.

@tbreloff
Copy link
Contributor

Ok thanks @dcjones. I'll use this example to dig through the code a little more.

Also a side point... I've started implementing real time updating through Plots, and the basics are working. I was pleasantly surprised at the performance of Immerse/Gadfly... See JuliaPlots/Plots.jl#30 (comment). Have you pushed performance improvements recently?

On Sep 25, 2015, at 3:10 AM, Daniel C. Jones [email protected] wrote:

@zywind There's not a built in way to do per-segment coloring per se, but you can fake it without too much effort by just making a separate line for each segment. Here's an example:

@tbreloff The hard-coded 1-index is applying scalar properties, for which there only is one element, so it's not discarding properties. If you want to draw line segments differently, you just have to split them into separate lines. That's how it works on most graphics backends (cairo, svg, etc), compose isn't peculiar in this regard. So coloring segments differently could just be implemented in Geom.line rather easily, by just automating what I did above.


Reply to this email directly or view it on GitHub.

@lobingera
Copy link

@tbreloff,

keep in mind that you update (in your example) something below 1000 points. Speed degradation in rendering with Cairo shows up in higher regions. In all my experiments using Gadfly rendering into a window, i was also successful drawing ~10-20ms.

@zywind
Copy link
Author

zywind commented Sep 25, 2015

Thanks @dcjones. I'll use your method for my code. It would be very nice if this is automated.

@tbreloff
Copy link
Contributor

@lobingera I started to worry that there was some underlying explosion in drawing time with additional points, so I threw together a test to time the time-to-update after adding 500 new points to each series repeatedly. The results are linear, which is good (and expected), although a highly optimized library might be able to go sub-linear by not drawing overlapping items. Results:

tmp

@tbreloff
Copy link
Contributor

For comparisons sake, though... here's the same test with Qwt as the backend. For this test, Qwt is about 4x faster (and the current implementation uses PyCall to access a python library PyQwt which then re-wraps a C++ library Qwt, which eventually draws to a QPainter object...)

tmp

@tbreloff
Copy link
Contributor

Back to the original question. This is not an easy thing to do with Gadfly, and there are limitations. You'll have to call it through Plots.jl (I haven't pushed the changes to master yet, but there's a great hack to do something like what Daniel did above), and here's how:

If you pass in the same number of colors as data points, it works as expected IF there are no duplicate colors:

tmp

This should work for paths too, which probably wouldn't work with Daniel's example:

tmp

But things start to break if you don't have enough colors:

tmp

Or if there are not enough unique colors:

tmp

I don't think these issues can be fixed easily, but maybe Daniel knows how.

@tbreloff
Copy link
Contributor

I just pushed up my changes to Plots... give it a try and see if it meets your needs.

@dcjones
Copy link
Collaborator

dcjones commented Sep 25, 2015

You can fix this using the group aesthetic:
screen shot 2015-09-25 at 1 48 47 pm

@tbreloff
Copy link
Contributor

I'm not totally sure why it works but it does! 👍
tmp

@Mattriks
Copy link
Member

The current best way to do this Gadfly is Geom.segment.

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

No branches or pull requests

6 participants