JuliaPlots / Plots.jl

Powerful convenience for Julia visualizations and data analysis
https://docs.juliaplots.org
Other
1.84k stars 354 forks source link

[FR] Colorbar properties #3174

Open rafaqz opened 3 years ago

rafaqz commented 3 years ago

It would be useful to be able to style additional attributes of colorbars, as discussed recently on slack in plotting

~- [ ] tick size~ ~- [ ] tick color~

My use-case is cleaner map-plotting recipes in GeoData.jl. Currently, if you stray too far from the defaults the colorbar starts to look out of place.

This could start with just GR?

related, but just for ticks: https://github.com/JuliaPlots/Plots.jl/issues/2308

mkborregaard commented 3 years ago

It's tricky because Plots development aims to keep keywords few(-ish), in order to keep maintainability. In general all new keywords should preferably be applied across all backends to keep interchangeability of backends. One possibility could be to adapt extra_kwargs to be able to pass colorbar kwargs, but this wouldn't work in recipes. I guess this requires a bit of discussion.

@rafaqz do you happen to know how many of these attributes are supported natively by e.g. GR?

hervasa2 commented 3 years ago

I think the colorbar should have the same attributes as an axis. For example just like you have xticks and xscale, the colorbar should be able to support cticks and cscale. I came across this limitation while attempting cscale = :log10 (also tried zscale = :log10) on a heatmap.

rafaqz commented 3 years ago

I can see how keeping the keyword scope down would be important! especially given the breadth of use cases Plots.jl has to deal with.

If we can use the same set of attributes as @hervasa2 suggests, (maybe with colorbar_ prefixed?) it would at least add less overhead in terms of new names for things.

I'm not sure what is possible with GR, the colorbar method doesn't have many arguments, but there is lot of global state that is incorporated somehow. It does seem possible to do with matplotlib, plotly, and pgfplots.

mkborregaard commented 3 years ago

So having a new keyword type colorbar in addition to Plot, Subplot, Axis and Series, and reusing Axis keywords while prepending colorbar_? That does sound like a neat design. Thoughts @daschw ?

rafaqz commented 3 years ago

Also I didn't read @hervasa2 comment properly, cticks etc is nice too for where x/y is usually used.

daschw commented 3 years ago

So having a new keyword type colorbar in addition to Plot, Subplot, Axis and Series, and reusing Axis keywords while prepending colorbar_? That does sound like a neat design. Thoughts @daschw ?

I think that sounds like a good approach.

hervasa2 commented 3 years ago

Yes colorbar_[keyword] with c[keyword] as an alias would be nice and intuitive. I think a minimal feature in GR (if not all axis attributes can be applied to the colorbar) would be colorbar_ticks, that way the user could manipulate the data behind the scenes and set manual ticks to achieve the desired result.

isentropic commented 3 years ago

There is clims at the moment

fhagemann commented 3 years ago

I would also very much welcome the ability of manipulating colorbar properties. Thanks for bringing this up!

tbeason commented 3 years ago

I'm also looking for this functionality. Asked for exactly this in Slack and was directed here

bcsj commented 3 years ago

I think it would be nice to be able to access the frame/border/axes of the colorbar as well, e.g. colorbar_frame/cframe=:box.

Gyoshi commented 3 years ago

related: #2345

isentropic commented 3 years ago

If anyone is willing to help out with the development of this, please help out with the testing in the PR

isentropic commented 3 years ago

@rafaqz and others, most of the requested changes have been merged, please let me know your comments. Currently only PyPlot backend supports the new colorbar args:

    :colorbar_fontfamily        => :match,
    :colorbar_ticks              => :auto,
    :colorbar_tickfontfamily    => :match,
    :colorbar_tickfontsize      => 8,
    :colorbar_tickfontcolor     => :match,
    :colorbar_scale             => :identity,
isentropic commented 3 years ago

currently no c_*** aliases are made yet, but let's first make sure this works

rafaqz commented 3 years ago

Thanks, I'll try to give some feedback in the next few days

isentropic commented 3 years ago

Naturally you'd need to use #master branch before we get a relase

rafaqz commented 3 years ago

These work perfectly for me. Although I'm not sure what the allowed values for colorbar_scale are?

It would be good to add a few controls for the colorbar border too, like color/width etc. Seems it may be easy to copy your PR now to add some related args :)

isentropic commented 3 years ago

colorbar_scale takes :log10, :log2 and :identity (same as axis). Regarding the border and the color, it is strange that you want to change it even. Right now pyplot has 5% border width of the main plot, and I have no idea what do you wish we could've controlled the color

rafaqz commented 3 years ago

Oh right yep scale works well too.

With color/width - there are situations where you don't want a border on the colorbar, or you want it to be less prominent. For example, if you use e.g. :border=:none the plot has no border, but the colorbar still has one, and it doesn't look great. You may also want to use e.g. a ligher grey border instead of black, or use a thinner border, to push the colorbar back and make the plot stand out more. That being said, the PyPlot colorbar does look alright as-is most of the time, GR less so.

But I can add this later.

hervasa2 commented 3 years ago

Thank you for working on this! colorbar_scale is working nicely; however now the problem is the color gradient itself. When the colorbar_scale is switched to :log10 the color gradient follows it likewise. Therefore, once colorbar_scale = :log10 is set only the colorbar changes, and not the actual colors on the heatmap. When I tried to manually fix this by using something like cgrad(:inferno, scale =:exp) I came across the bug reported on #3420. pyplot no longer respects a color gradient's scale

isentropic commented 3 years ago

Right, I've been aware of this for a while. The attempt to fix was here #3432. I need some additional testers

isentropic commented 3 years ago

Right now this is a pyplot issue right? I just want to make sure that simplest behavior is still functional. Please let me know if

  1. Normal linear scale colorbars work as intended with pyplot
  2. Markers are not properly colored with the log scale colorbar.
hervasa2 commented 3 years ago

Thanks for your quick response! Yes this is a pyplot issue only.

  1. Normal linear scale colorbars work as intended with pyplot. Base functionality looks fine.
  2. Markers are not properly colored with the log scale colorbar. This applies both to the cases where one uses colorbar_scale = :log or when color = cgrad(:inferno, scale =:log)

In the meantime I will test #3432

hervasa2 commented 3 years ago

I think the first order of business would be to get color = cgrad(:inferno, scale =:log) working again since this is something that was broken. Then I like the axis formatter approach suggested by @isentropic in #3432:

"Can't Plots just provide axis formatters? For example: I am plotting a 10^2, 10^3, 10^4 (three points) in log scale, Then, Plots would just log it to get -> (2, 3, 4) Then, just decorate the axis labels as (10^2, 10^3, 10^4) (instead of natural 2,3,4)"

isentropic commented 3 years ago

I'm not sure how to handle colorbars with log scale right now. I don't think we should focus on (cgrad=:log) just yet. In the pr Cscale=log produces normal looking colorbar (color transition in the gradient looks uniform). However the markers are wrong color.

The problem is that I'm not so sure where Plots assigns marker colors to the points . If someone has an idea do let me know.

BeastyBlacksmith commented 3 years ago

Marker colors are stored in the marker_z seriesattribute, but maybe I got the question wrong

isentropic commented 3 years ago

Yes, I'm aware of that, but where does it get assigned? Somewhere in the depths of the pipeline but I could not find where

BeastyBlacksmith commented 3 years ago

Aren't those given from the callsite? Or do you have examples where there is automatic color assignment?

isentropic commented 3 years ago

In case of the colorbar, I think the colors need to be assigned somehow? Perhaps I'm missing something here but I thought marker color gets overriten when a colobar is present

BeastyBlacksmith commented 3 years ago

Its the other way around. You get a colorbar of you got marker_z values. How should Plots now what values to put there?

isentropic commented 3 years ago

@hervasa2 @rafaqz checkout the PR https://github.com/JuliaPlots/Plots.jl/pull/3620

isentropic commented 3 years ago

need testing and feedback from you

henry2004y commented 2 years ago

Thanks for the work on this! Is there any progress especially on the log scale colorbar? What is stopping us from merging #3620?

isentropic commented 2 years ago

Lack of testing and user feedback

isentropic commented 2 years ago

That PR is outdated I believe, given a large demand I could revise it.

henry2004y commented 2 years ago

Hmm, I don't know if I myself can be representative for a large demand... But for certain the lack of smooth support of log scale colormap/colorbar is one of the reasons I would still prefer matplotlib in production work. I don't feel urgent on this feature since we do have other alternatives, but it's good to have one and maybe I can help test the features and give feedbacks.

isentropic commented 2 years ago

The reason I'm hesitant to merge it is that the colors did not look right to me sometimes. Dangerous decision to plot something that is not representing the actual data. Need to test this thoroughly.

My personal workaround is just to log the data preemptively.

henry2004y commented 2 years ago

I actually have a use case where taking the log on the data cannot work: a histogram2d with weights.

x = rand(1000)
y = rand(1000)
w = 10 .^(10 .* rand(1000))
histogram2d(x, y, nbins=20, weights = w)

In this case I really need a log scale colorbar.

rafaqz commented 2 years ago

Lack of testing and user feedback

Sorry I thought I had already tested the new functionality and it was merged?

What was added with the second PR that was different to before? A description for the PR would help with feedback.

isentropic commented 2 years ago

The second PR actually fixes logscale colors

isentropic commented 2 years ago

First time the color reflected in the colorbar was not matching the data

zhiyuanzhai commented 2 years ago

Other backend are still to support the colorbar_scale feature. For example, with PGFPlotsX:

image
CantelopePeel commented 1 year ago

any plan to propagate the log colorbar support to other backends?

t-bltg commented 1 year ago

It should work for the pythonplot backend after https://github.com/JuliaPlots/Plots.jl/pull/4542.

See an example usage in https://github.com/JuliaPlots/Plots.jl/pull/3620.

cmdenis commented 3 months ago

Has there been any updates in adding these functionalities to the GR backend?