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

Provide color vector along with levels in contours? #118

Open
maxlarsen opened this issue Jan 29, 2016 · 15 comments
Open

Provide color vector along with levels in contours? #118

maxlarsen opened this issue Jan 29, 2016 · 15 comments
Labels
enhancement improving existing functionality

Comments

@maxlarsen
Copy link

Hello,

Is it currently possible to provide a vector of n-1 colors along with n levels for a filled contour plot? I tried very hard but I was not able to figure it out. It seems the color= option always falls back on the gradient method which does not work for me.

Explanation: maybe my function f(x,y) takes values on [0,10] but all of the action is between 9.9 and 10, and I want "equally spaced colors" on the levels [0,5,9,9.5,9.9,9.95,9.99,10]. This is quite natural in eg. an optimization context. Right now what I managed to obtain was always an almost indistinguishable gradient on a "narrow range" (9.9-10 out of 0-10 in the example).

More generally, I think a reasonable heuristic would be to automatically define value bins such that each bin has as many points : each colored region would have approximately the same area. I understand that the current heuristic which picks more distinct colors when the values are further away is also useful, so this could be an alternative heuristic somehow. Just throwing the idea in the air, I would be very happy with a manual vector of colors already.

Amazing job on this package by the way. Thanks a lot!

Max

@tbreloff
Copy link
Member

You can create your own gradients and vectors directly and pass them in... here's an example that I hope shows how to do this:

tmp

Hopefully this helps. I don't have the color functionality well documented, so for right now you might need to just ask for specific help here when you can't figure it out.

@maxlarsen
Copy link
Author

Hey thanks a lot, worked flawlessly! I don't understand how it works though, would you mind shedding some light on what role the [x,y,z] argument plays exactly?

@tbreloff
Copy link
Member

Sure. It's what you were asking for (I think)... A vector of cutoff points. The values are expected to be between 0 and 1, and correspond to bucket endpoints. So in this example a z-value of [0.975 * (maxval - minval) + minval] will be mapped to the equivalent of 75% of a "normal" gradient. Does that explain it ok?

On Jan 28, 2016, at 10:25 PM, maxlarsen notifications@github.com wrote:

Hey thanks a lot, worked flawlessly! I don't understand how it works though, would you mind shedding some light on what role the [x,y,z] argument plays exactly?


Reply to this email directly or view it on GitHub.

@maxlarsen
Copy link
Author

OK so I did some more tests and for the sake of completeness and for anyone reading this it looks like ColorGradient(:heat,[x1,x2,x3,...]) is in fact ColorGradient(:heat,[0,x,1]). I was being bitten by the fact that if you give it more than 3 values, it silently ignores the input:

xx=linspace(-1,1,100)
yy=xx
ff(x,y)=pdf(MvNormal([0.,0],[3. 2;2 3]),[x,y])
gg=[ff(x,y)::Float64 for x=xx,y=yy]
qlevels=[0,.25,.5,.75,0.8,0.9,0.95,0.975,0.99,1]
levels=quantile(vec(gg),qlevels)

contour(xx,yy,gg,fill=true,levels=levels,c=:heat)
contour(xx,yy,gg,fill=true,levels=levels,c=ColorGradient(:heat,[0,0.1,0.95,1]))
contour(xx,yy,gg,fill=true,levels=levels,c=ColorGradient(:heat,[0,0.1,0.8,1]))
contour(xx,yy,gg,fill=true,levels=levels,c=ColorGradient(:heat,[0,0.8,0.95,1]))

all plot the same thing on my machine.

So if I understand correctly you cannot as of now pick m colors, m bins and apply the colors to the bins. But you can "increase the contrast" on one end or the other by feeding ColorGradient(:heat,[0,0.20,1]) or ColorGradient(:heat,[0,0.80,1]).

Given the issue title I could leave this open as a feature request. On the other hand ColorGradient(:heat,[0,0.80,1]) does the job for me and I am happy to close! Let me know. Thanks in any case.

@tbreloff
Copy link
Member

Which backend are you using? What version of Plots?

If I understand, you want to be able to specify the exact contour levels and assign colors manually? This may be possible, but I'd need to look at the code again.

On Jan 29, 2016, at 8:37 AM, maxlarsen notifications@github.com wrote:

OK so I did some more tests and for the sake of completeness and for anyone reading this it looks like ColorGradient(:heat,[x1,x2,x3,...]) is in fact ColorGradient(:heat,[0,x,1]). I was being bitten by the fact that if you give it more than 3 values, it silently ignores the input:

xx=linspace(-1,1,100)
yy=xx
ff(x,y)=pdf(MvNormal([0.,0],[3. 2;2 3]),[x,y])
gg=[ff(x,y)::Float64 for x=xx,y=yy]
qlevels=[0,.25,.5,.75,0.8,0.9,0.95,0.975,0.99,1]
levels=quantile(vec(gg),qlevels)

contour(xx,yy,gg,fill=true,levels=levels,c=:heat)
contour(xx,yy,gg,fill=true,levels=levels,c=ColorGradient(:heat,[0,0.1,0.95,1]))
contour(xx,yy,gg,fill=true,levels=levels,c=ColorGradient(:heat,[0,0.1,0.8,1]))
contour(xx,yy,gg,fill=true,levels=levels,c=ColorGradient(:heat,[0,0.8,0.95,1]))
all plot the same thing on my machine.

So if I understand correctly you cannot as of now pick m colors, m bins and apply the colors to the bins. But you can "increase the contrast" on one end or the other by feeding ColorGradient(:heat,[0,0.20,1]) or ColorGradient(:heat,[0,0.80,1]).

Given the issue title can I leave this open as a feature request?


Reply to this email directly or view it on GitHub.

@maxlarsen
Copy link
Author

pyplot() back-end and:

 - Gadfly                        0.4.2
 - Plots                         0.5.1
 - PyPlot                        2.1.1
 - UnicodePlots                  0.1.1
 - Winston                       0.11.13

Yes, I feel like:

contour(xx,yy,gg,fill=true,levels=[z1,z2,z3,z4,z5],c=uniformgradient(:heat,4))

would often be useful. (or maybe uniformpalette or something: 4 equally spaced colors along a gradient). If I have:

contour(xx,yy,gg,fill=true,levels=[z1,z2,z3,z4,z5],c=mycolorvector)

It is even more flexible and I can probably figure out an external way to come up with mycolorvector=uniformgradient(:heat,4) (although I feel like you did a great job with colors in this package so it would be great to be able to access your palettes, gradients etc.)

I would personnally very quickly wrap this in:

function qcontour(xx,yy,gg,quantilelevels)
    levels=quantile(vec(gg),quantilelevels)
    contour(xx,yy,gg,fill=true,levels=levels,color=uniformgradient(:heat,length(quantilelevels)-1))
end

Then I could call qcontour(xx,yy,gg,[0,.25,.5,.75,.9,.95,1]) and obtain 6 well-distinct colors for my bins, even when the values are very close, eg [0.9-0.95] and [0.95-1].

Finally:

econtour(xx,yy,gg,n)=qcontour(xx,yy,gg,levels=linspace(0,1,n+1))

and econtour(xx,yy,gg,6) will cut the z values in 6 bins of equal number of observations and give well-distinct colors for each of those.

Of course with those approaches I will lose the color-clue of height, but I can obtain a more precise sense of multimodalities, where the maxima are etc. even on flat regions.

@tbreloff
Copy link
Member

I think you've uncovered a bug... I'm looking into it.

@tbreloff
Copy link
Member

Ok I think I figured it out (and hopefully I didn't break anything else in the process!!!) I pushed up some changes to the dev branch. If you wouldn't mind, could you do a Pkg.checkout("Plots", "dev") and see if it works as expected now? Here's a slight modification of your example:

tmp

@maxlarsen
Copy link
Author

What is it supposed to do? It clearly does provide better visibility in the example above but it does not look like it take "uniformly spaced" colors and puts them in the corresponding nlevels-1 bins:

using Plots, Distributions
xx=linspace(-1,1,100)
yy=xx
ff(x,y)=pdf(MvNormal([0.,0],[3. 2;2 3]),[x,y])
gg=[ff(x,y)::Float64 for x=xx,y=yy]
qlevels=[0,0.1,0.2,1]
levels=quantile(vec(gg),qlevels)

contour(xx,yy,gg,fill=true,levels=levels,c=:heat)    #figure 4
contour(xx,yy,gg,fill=true,levels=levels,c=ColorGradient(:heat,qlevels)) #figure 5

image

levels does the right thing: I have a region with the lowest 10% values, one with the next 10% lowest and the 80% rest. But Figure 5 uses the qlevels option and the colors are "less equally spaced" than without the keywords....

Didn't have time to play around much

@tbreloff
Copy link
Member

I'll be honest that this seems more like a PyPlot idiosyncrasy. See for example this answer: http://stackoverflow.com/questions/15601096/contour-graph-in-python

In the linked graph, notice that the colors in the right hand graph are light blue and orange, which correspond to 0.25 and 0.75. You could definitely argue that those colors should correspond to 0 and 1 (dark blue and dark red), but that's not what PyPlot does.

The correct solution may be to "compress" the gradient for PyPlot and essentially trick it to use the colors we want. I don't love the idea of doing that automatically but it might work ok. I'll think on this more, and please post more examples (with a description of desired functionality) if you think of them.

On Jan 29, 2016, at 7:03 PM, maxlarsen notifications@github.com wrote:

What is it supposed to do? It clearly does provide better visibility in the example above but it does not look like it take "uniformly spaced" colors and puts them in the corresponding nlevels-1 bins:

using Plots, Distributions
xx=linspace(-1,1,100)
yy=xx
ff(x,y)=pdf(MvNormal([0.,0],[3. 2;2 3]),[x,y])
gg=[ff(x,y)::Float64 for x=xx,y=yy]
qlevels=[0,0.1,0.2,1]
levels=quantile(vec(gg),qlevels)

contour(xx,yy,gg,fill=true,levels=levels,c=:heat) #figure 4
contour(xx,yy,gg,fill=true,levels=levels,c=ColorGradient(:heat,qlevels)) #figure 5

levels does the right thing: I have a region with the lowest 10% values, one with the next 10% lowest and the 80% rest. But Figure 5 uses the qlevels option and the colors are "less equally spaced" than without the keywords....

Didn't have time to play around much


Reply to this email directly or view it on GitHub.

@tbreloff
Copy link
Member

For clarity, let me expand on the ColorGradient constructor. What you are doing is setting the "anchor colors" of the gradient to new positions (this has nothing to do with contours/levels yet, as you're only building the gradient).

An example will help. Suppose there are 3 colors in the original gradient: red, green, blue. You sample from the gradient where z=0 gives you red, z=0.5 gives you green, and z=1 gives you blue. z=0.25 interpolates halfway between red and green, etc.

Now if you instantiate the gradient with new anchor points, you are "warping" the gradient. Hopefully these examples will help you understand (checkout latest dev branch for this to work... I pushed one more fix):

screen shot 2016-01-30 at 10 05 53 am

Gradient construction is separate from the issues of:

  • PyPlot color choices for contours (need hack to fix their bad logic?)
  • Helper functions to automatically find good "anchor colors" given a data distribution

@maxlarsen
Copy link
Author

Makes sense. I guess my view is that rather than hacking the gradient functions, at some point it is more convenient to be able to feed a color vector to obtain the visualization you want. Looks like you can do it in matplolib with ListedColormap see here. I don't know if you are interested in considering this option for Plots.jl (regardless of the back-end). Cycling over colors would be a good default behavior if the number of colors is not the same as the number of bins.

@tbreloff tbreloff added the enhancement improving existing functionality label May 4, 2016
@mkborregaard
Copy link
Member

@maxlarsen check this PR on PlotUtils, I think that will allow you to do this by registering the color vector as a gradient and then use it by name for further plots.

JuliaPlots/PlotUtils.jl#5

@tbreloff
Copy link
Member

tbreloff commented Nov 7, 2016

Sadly I don't think it's this simple. (Otherwise this should be closed)
The problem is in defining specific colors for each contour level, and
circumventing the gradient mechanism.

On Monday, November 7, 2016, Michael Krabbe Borregaard <
notifications@github.com> wrote:

@maxlarsen https://github.com/maxlarsen check this PR on PlotUtils, I
think that will allow you to do this by registering the color vector as a
gradient and then use it by name for further plots.

JuliaPlots/PlotUtils.jl#5
JuliaPlots/PlotUtils.jl#5


You are receiving this because you commented.
Reply to this email directly, view it on GitHub
#118 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AA492ucFNAlS0odld13SCwkxbKz4rcUfks5q7wfzgaJpZM4HO0qz
.

@mkborregaard
Copy link
Member

You're right, I didn't understand the issue properly.
But then I think this request is related to my other issue: JuliaPlots/PlotUtils.jl#3 , where classes would take the levels attribute and gradtype would be :custom.

t-bltg pushed a commit that referenced this issue Oct 6, 2022
t-bltg added a commit that referenced this issue Oct 6, 2022
* use Dates

* Add compat for RecipesBase

* Fix badges

* Plots test

* Fix travis

* Forgot using

* Update .travis.yml

Co-Authored-By: Anshul Singhvi <asinghvi17@simons-rock.edu>

* Use ds/rewrite

* Try with --project


Credit: Fredrik Ekre

* Use latest stable julia version

* Allow failures on MacOS

* Docs deployment

* Literate + enable deploy

* Update Project.toml

* fix missing comma

* Fix error

* try fixing repo name

* small change to trigger CI

* play better with Literate

* allow type recipes for `Number`s in arrays and surfaces

* small fixes

* skip maybestrings

* fix ambiguity

* Add badge

* Fix build badge link

* Show status only for master branch

* Fix README docs link

* remove subdomain

* Create TagBot.yml

* fix surface type recipe

* bump version

* fix error for grouping

* bump version

* further grouping fixes

* bump version

* fix plotting functions

* bump version

* downgrade version

* fix plotting rowvector of functions

* bump version

* support parametric type in `@userplot`

* add docs for parametric type in `@userplot`

* bump version

* fix grouping

* bump version

* bump PlotUtils compat

* bump version

* add zulip chat link to readme [skip ci]

* add zulip link [skip ci]

* Fix typo in docs

`AbstractArry` -> `AbstractArray`

* add hook after series decomposition (#52)

* add process_sliced_series_attributes!

* export process_slice_series_attrributes!

* remove `kw`

* Update Project.toml

[skip ci]

* Initial pass at CI

* Add script from Plots

* Update to MakieRecipes

* comment out artifact uploads

* Plots test

* CairoMakie tests

* Forgot using

* Update .travis.yml

Co-Authored-By: Anshul Singhvi <asinghvi17@simons-rock.edu>

* Use ds/rewrite

* Try with --project

* Another try

Credit: Fredrik Ekre

* Import examples from MakieRecipes

* add separately

* dev

* $(mktemp -d)

* Update .github/workflows/CI.yml

Co-Authored-By: Anshul Singhvi <asinghvi17@simons-rock.edu>

* use temp_for_test

* fix typo

* Update .github/workflows/CI.yml

* ensure that images are uploaded

* Pass a begin block to testset

* fix the macro

* seriously, I forgot .png?

* Update .travis.yml

* Fix split_attribute (#53)

* Fix a typo in the `recipe_pipeline!` constructor (#54)

* bump version

* fix time and period recipes

* bump version

* Fix typo (#56)

* implement `Base.axes` for `Volume`

* bump version

* Update group.jl

* implement iterate for Surface and Volume

* bump version

* use NaNMath log functions

* Add one_arg_shorthands macro (#73)

* Add one_arg_shorthands macro

* export one_arg_shorthands

* patch version [skip ci]

* Add :mesh3d as 3d series type (#62)

* 0.1.12 [skip ci]

* add compat for NaNMath

* dispatch processing of axis args on the plot object (#63)

* dispatch processing of axis args on the plot object

* Update type_recipe.jl

* Update type_recipe.jl

* Update type_recipe.jl

* add to API

* Update api.jl

* 0.1.13

* remove one_arg_shorthands macro (#74)

It didn't work out as intended

* 1.1.0

* more friendly error when x,y shape mis-match

* AbstractDict plot sorted

* more friendly error when x,y shape mis-match (#65)

* more friendly error when x,y shape mis-match

* don't touch z

* Update src/user_recipe.jl

Co-authored-by: Daniel Schwabeneder <daschw@disroot.org>

* switch to github-actions and update runtests.jl to run Plots test images

* update CI.yml

* keep makie tests

* move `signature_string` to RecipesPipeline

* minor version bump

* Revert "minor version bump"

This reverts commit 63c713b7808adf305484a9724cef9eabae2a0702.

* move `warn_on_recipe_aliases!` from Plots and add some `@nospecialize`

* add CompileBot

* minor version bump

* add precompile statements

* bump version

* add new line at end of file

* add recipe for list of NamedTuples

* add newline

* update tagbot action

* add recipe for list of NamedTuples

* move `warn_on_recipe_aliases!` from Plots and add some `@nospecialize`

* update tagbot action

* Fix broken histogram and stepbins plotting

* Increase package version to v0.2.1

* Update precompile_*.jl file

* add TestImages test dependency

* refine friendly error (#75)

* Update precompile_*.jl file

* don't stringify argument to `warn_on_recipe_aliases!` early
needs matching Plots changes

* minor release

* add `@nospecialize` annotations

* release

* update CompileBot

* update TESTCMD in CI

* fix TESTCMD in compilebot action

* Update precompile_*.jl file

* release

* Update README.md

[skip ci]

* don't catch all the MethodErrors (#87)

* don't catch all the MethodErrors

* remove `@show`

* 0.3.3 [skip ci]

* add mesh3d for GR

* v0.3.4

* Small improvement in inferrability (#82)

* 1.1.2 [skip ci]

* CI: tentative fix

* CI: add LinearAlgebra (#96)

Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>

* Test for error value from `apply_recipe` fallback. (#95)

* v0.3.5 [skip ci]

* Add `Downloads` test dependency

Complement #3766

* Remove try/catch needed for compatibility with Plots.jl v1.21.0 and earlier (#97)

* Improve groups perf from O(MxN) to O(M) (#98)

* Update MakieRecipes URL

* Update precompile_*.jl file (#91)

* v0.3.6 [skip ci]

* Revert try/catch for patch version

* v0.3.7 (#101) [skip ci]

* v0.4.0 (#102) [skip ci]

* Avoid Vararg UnionAll dispatch (#104)

* Avoid Vararg UnionAll dispatch

Fixes JuliaPlots/RecipesPipeline.jl#103

* fix fix

Co-authored-by: Simon Christ <SimonChrist@gmx.de>

* 0.4.1 [skip ci]

* move layout macro from plots (#85)

* 1.2.0 [skip ci]

* remove pct

* 1.2.1 [skip ci]

* Update Project.toml

* respect defaults for fillrange and ribbon (#106)

* respect defaults for fillrange and ribbon

* remove fillrange and ribbon handling from RecipesPipeline

* update ci

* set version

* Update CI.yml

* move documentation to gh-actions

* update run commands

* Update Documentation.yml

* Allow `NanMath` 1.0 - bump version (#108)

Co-authored-by: t-bltg <tf.bltg@gmail.com>

* Fix `unzip` for empty vectors (#110)

* 0.5.2 [skip ci]

* update url with https://docs.juliaplots.org/stable/generated/supported/#Keyword-Arguments (#89)

* Update precompile_*.jl file (#109)

Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>

* run  snoopcompile on pust to master only

* update compat bounds (#111)

* 0.6.0 [skip ci]

* Update precompile_*.jl file (#112)

Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>

* `SnoopCompile` labels

* use ssh key for `TagBot` (#91)

* fix julia scripts in markdown (#90)

* add missing language specification in md

* replace type with struct

* fix `SnoopCompile` (#113)

* update compat bounds

* run snoop on master only

* update precompile

* Update precompile_*.jl file (#114)

Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>

* 0.6.1 [skip ci]

* fix plotting `Union{Missing,Real}` arrays (#116)

* Update precompile_*.jl file (#115)

Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>

* 0.6.2 [skip ci]

* fix formatters (#118)

* 0.6.3 [skip ci]

* Update precompile_*.jl file (#117)

Co-authored-by: BeastyBlacksmith <BeastyBlacksmith@users.noreply.github.com>

* Create invalidations.yml (#93)

This is based on https://github.com/julia-actions/julia-invalidations. Adding such checks came up in https://discourse.julialang.org/t/potential-performance-regressions-in-julia-1-8-for-special-un-precompiled-type-dispatches-and-how-to-fix-them/86359. I suggest to add this check here since this package is widely used as a dependency.

* rework precompilation using `SnoopPrecompile` - document `@layout` (#94)

* document `@layout`

* rewok precompile statements using `SnoopPrecompile`

* add ci

* bump julia to `1.6` for failing CI

* 1.3.0

* more efficient `DefaultsDict` iteration (#121)

* bump julia version in `ci` (#122)

* 0.6.4

* Add methods to access separate keysets of the DefaultsDict (#124)

* bump version [skip ci]

* DefaultsDict - correctness and performance tweaks for large numbers of series (#126)

* 0.6.6 [skip ci]

* Fix a deprecated syntax in docs of macro `@recipe` (#95)

* fix broken docs

* remove

* remove un-needed files

* RP tests

Co-authored-by: Daniel Schwabeneder <daschw@disroot.org>
Co-authored-by: Sebastian Micluța-Câmpeanu <m.c.sebastian95@gmail.com>
Co-authored-by: Sebastian Micluța-Câmpeanu <31181429+SebastianM-C@users.noreply.github.com>
Co-authored-by: Anshul Singhvi <asinghvi17@simons-rock.edu>
Co-authored-by: Lirimy <31124605+Lirimy@users.noreply.github.com>
Co-authored-by: mtsch <matijacufar@gmail.com>
Co-authored-by: Simon Christ <SimonChrist@gmx.de>
Co-authored-by: JonasIsensee <jonas.isensee@web.de>
Co-authored-by: Michael Abbott <me@pseudomac>
Co-authored-by: Benoit Pasquier <4486578+briochemc@users.noreply.github.com>
Co-authored-by: Michael Krabbe Borregaard <mkborregaard@snm.ku.dk>
Co-authored-by: Adrian Dawid <dwd31415@users.noreply.github.com>
Co-authored-by: Moelf <proton@jling.dev>
Co-authored-by: Oliver Schulz <oschulz@mpp.mpg.de>
Co-authored-by: daschw <daschw@users.noreply.github.com>
Co-authored-by: Moelf <Moelf@users.noreply.github.com>
Co-authored-by: Jeremy Bejanin <jeremy.bejanin@gmail.com>
Co-authored-by: t-bltg <t-bltg@users.noreply.github.com>
Co-authored-by: Tim Holy <tim.holy@gmail.com>
Co-authored-by: Nicholas Bauer <nicholasbauer@outlook.com>
Co-authored-by: Mike Keehan <21029749+mdkeehan@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Christopher Rackauckas <chrisrackauckas@gmail.com>
Co-authored-by: Kristoffer Carlsson <kcarlsson89@gmail.com>
Co-authored-by: Yuto Horikawa <hyrodium@gmail.com>
Co-authored-by: Rafael Schouten <rafaelschouten@gmail.com>
Co-authored-by: MrHenning <5331081+MrHenning@users.noreply.github.com>
Co-authored-by: BeastyBlacksmith <BeastyBlacksmith@users.noreply.github.com>
Co-authored-by: Hendrik Ranocha <ranocha@users.noreply.github.com>
Co-authored-by: Ryan <25192197+singularitti@users.noreply.github.com>
Jonas-a-Zimmermann pushed a commit to Jonas-a-Zimmermann/Plots.jl that referenced this issue Oct 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement improving existing functionality
Projects
None yet
Development

No branches or pull requests

3 participants