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

Plots should check RGB values don't contain invalid values - Inexact error plotting image in gr() #851

Closed
dlfivefifty opened this issue May 21, 2017 · 22 comments
Labels

Comments

@dlfivefifty
Copy link
Contributor

dlfivefifty commented May 21, 2017

gr()
x=y=range(-1.0,1.0; length=1000)
img = RGB.(x.+x',x.+x',x.+x')
plot(img)

Throw

InexactError()

 in (::Plots.##180#184)(::ColorTypes.RGB{Float64}) at /Users/solver/.julia/v0.5/Plots/src/backends/gr.jl:959
 in collect_to!(::Array{UInt32,2}, ::Base.Generator{Array{ColorTypes.RGB{Float64},2},Plots.##180#184}, ::Int64, ::Int64) at ./array.jl:340
 in _collect(::Array{ColorTypes.RGB{Float64},2}, ::Base.Generator{Array{ColorTypes.RGB{Float64},2},Plots.##180#184}, ::Base.EltypeUnknown, ::Base.HasShape) at ./array.jl:321
 in map(::Function, ::Array{ColorTypes.RGB{Float64},2}) at ./abstractarray.jl:1691
 in gr_display(::Plots.Subplot{Plots.GRBackend}, ::Measures.Length{:mm,Float64}, ::Measures.Length{:mm,Float64}, ::Array{Float64,1}) at /Users/solver/.julia/v0.5/Plots/src/backends/gr.jl:959
 in gr_display(::Plots.Plot{Plots.GRBackend}) at /Users/solver/.julia/v0.5/Plots/src/backends/gr.jl:500
 in _show(::Base.AbstractIOBuffer{Array{UInt8,1}}, ::MIME{Symbol("image/svg+xml")}, ::Plots.Plot{Plots.GRBackend}) at /Users/solver/.julia/v0.5/Plots/src/backends/gr.jl:1098
 in show(::Base.AbstractIOBuffer{Array{UInt8,1}}, ::MIME{Symbol("image/svg+xml")}, ::Plots.Plot{Plots.GRBackend}) at /Users/solver/.julia/v0.5/Plots/src/output.jl:197
 in show(::Base.AbstractIOBuffer{Array{UInt8,1}}, ::MIME{Symbol("text/html")}, ::Plots.Plot{Plots.GRBackend}) at /Users/solver/.julia/v0.5/Plots/src/output.jl:177
 in show(::Base.AbstractIOBuffer{Array{UInt8,1}}, ::String, ::Plots.Plot{Plots.GRBackend}) at ./multimedia.jl:33
 in #sprint#316(::Void, ::Function, ::Int64, ::Function, ::String, ::Vararg{Any,N}) at ./strings/io.jl:37
 in display_dict(::Plots.Plot{Plots.GRBackend}) at /Users/solver/.julia/v0.5/Plots/src/output.jl:266
 in execute_request(::ZMQ.Socket, ::IJulia.Msg) at /Users/solver/.julia/v0.5/IJulia/src/execute_request.jl:187
 in eventloop(::ZMQ.Socket) at /Users/solver/.julia/v0.5/IJulia/src/eventloop.jl:8
 in (::IJulia.##13#19)() at ./task.jl:360
@mkborregaard
Copy link
Member

cc @jheinen

@mkborregaard
Copy link
Member

mkborregaard commented May 21, 2017

Not sure this is a bug, though? The error is thrown when parsing RGB{Float64}(2.0,2.0,2.0) - but that shouldn't be defined, right? The results doesn't fit into a UInt32 which is the format used to hold the colors, and that is why the InexactError is thrown. Nor should RGB{Float64}(-2.0,-2.0,-2.0) be defined, according to the definition of the RGB type https://github.com/JuliaGraphics/ColorTypes.jl/blob/367821e5f1860ce5d10419f2c3616824c0fe2b5f/src/types.jl#L76-L79 , but half of the RGB values in the MWE are negative.

@dlfivefifty
Copy link
Contributor Author

dlfivefifty commented May 21, 2017 via email

@mkborregaard
Copy link
Member

Yes possibly. Do you want to open an issue on ColorTypes or should I? Closing the issue here.

@mkborregaard mkborregaard reopened this May 21, 2017
@mkborregaard mkborregaard changed the title Inexact error plotting image in gr() Plots should check RGB values don't contain invalid values - Inexact error plotting image in gr() May 21, 2017
@mkborregaard
Copy link
Member

mkborregaard commented May 21, 2017

After the discussion here JuliaGraphics/ColorTypes.jl#85 it transpires that downstream packages should check for RGB validity, as that cannot be done automatically. The suggestion is to use convert(RGB{N0f8}, c) where N0f8 is FixedPointNumbers.Normed{UInt8,8} - this throws an appropriate error message. This should possibly be done everywhere an RGB is used (also in PlotUtils) rather than just in gr.jl so the design will require a little thought.

@JeffBezanson
Copy link
Contributor

There is a similar issue with grayscale (or "scalar") images that might be easier to resolve. You get an InexactError if there are values outside [0,1]. Other image showing methods, e.g. the show method for image/png clamp the values. (I'd actually prefer they rescale the values and not just clamp them, but that's a separate debate :) )

FWIW, it doesn't matter to me what happens to "invalid" colors used in other contexts; e.g. it's fine to get a random error if I try to use an RGB value with negative components as the color of a line. Visualizing arbitrary arrays of floats as grayscale images is a very common and important use case though.

@mkborregaard
Copy link
Member

So you mean plot(Gray.(mymatrix))?
That should be easy enough to fix here

Plots.jl/src/series.jl

Lines 327 to 340 in 57da253

@recipe function f(mat::AMat{T}) where T<:Gray
n, m = size(mat)
if is_seriestype_supported(:image)
seriestype := :image
yflip --> true
SliceIt, 1:m, 1:n, Surface(mat)
else
seriestype := :heatmap
yflip --> true
cbar --> false
fillcolor --> ColorGradient([:black, :white])
SliceIt, 1:m, 1:n, Surface(convert(Matrix{Float64}, mat))
end
end

@mkborregaard
Copy link
Member

or do you mean heatmap(mymatrix, color = :Grays, clims = (0,1))

@JeffBezanson
Copy link
Contributor

I mean plot(Gray.(mymatrix)). See also JuliaImages/ImageShow.jl#7.

@mkborregaard
Copy link
Member

mkborregaard commented Jan 21, 2019

Sure I'll implement the common format that's agreed on there, though I've got a comment.

@mkborregaard
Copy link
Member

When the backend supports images, true for GR and PyPlot, Plots is not responsible for showing the images, so the only possibility we have this side is to copy the image into a new, clamped, image before passing to the backend. This is costly of course - @jheinen do you know if GR has clamping functionality we could tap into directly in the backend? And who knows about the PyPlot backend - @daschw?

For backends that don't support images, Plotly(JS), PGFPlots, InspectDR, UnicodePlots, we already copy the input and so the fix is unproblematic.

@daschw
Copy link
Member

daschw commented Jan 22, 2019

Apparently, pyplot does the clamping, but it does not use the correct color gradient:

julia> mat = 10*rand(10, 10) .- 4.5
10×10 Array{Float64,2}:
  3.60483   -3.12377     3.33383   -0.685487  -4.21144    0.317257   1.58456   -0.59569   -0.48613    4.89837
  3.58926    0.639327    1.80893   -2.40848   -1.29764    2.01744    4.31696   -3.11538   -1.40745   -3.26707
  4.40075   -2.14372    -0.177826   0.252664   0.798815   3.42435   -1.07678    4.71595    1.83117   -4.0745
  0.999101   0.692926    0.918787   3.28246    0.248259  -0.332062  -3.56485    3.96771    4.53913   -2.82667
 -1.37461    2.02262     4.27795   -1.86656    1.91002   -4.31299    0.203546   1.31932   -1.77117   -2.14512
 -2.56787   -1.27978     1.58763   -1.54383   -0.790331  -3.3783     3.53132    3.58427    4.07261    1.88834
 -0.943326   0.610132   -3.56748    3.61886   -1.29139    1.18342    2.62486   -4.09862   -1.65401   -1.17085
  3.28029   -4.43863     1.82443   -3.74372    1.95606   -4.3604     4.39168    4.25667    4.55647   -4.47998
  4.85202    4.91935     2.82812   -0.416751   0.851981  -2.48824    4.25222    3.39537   -0.961201  -2.65786
 -2.40401   -0.0256798   2.7577     3.04841    2.71774   -1.42594   -1.23693   -0.811501   0.729003  -1.84051

julia> plot(Gray.(mat))

pyplot_image

@mkborregaard
Copy link
Member

ugh, is that us or native pyplot as well?

@daschw
Copy link
Member

daschw commented Jan 22, 2019

it's us - fixed in #1899

@mkborregaard
Copy link
Member

Sweet - is it automatic in PyPlot then and we only need to worry about GR?

@daschw
Copy link
Member

daschw commented Jan 22, 2019

Yes, we set the clamping values for matplotlib's imshow in the pyplot backend code.

@mkborregaard
Copy link
Member

OK, so your PR did fix the colors but pyplot's image still acts very weirdly on my Mac. See https://www.dropbox.com/s/zsrojfqwlve3jfn/Recording%20%2314.mp4?dl=0 the image breaks down over a certain size. Also, the clamp code doesn't seem to really be working, as there is an overflow warning from Python (see the video)

Here's a wip pr for the clamping, so far just the heatmap-approach: #1900

@daschw
Copy link
Member

daschw commented Jan 23, 2019

I cannot reproduce the weird pyplot behaviour from your video on windows.

@mkborregaard
Copy link
Member

Hilarious

@mkborregaard
Copy link
Member

I'm going to implement the copy for now, but only do it if any of the values are outside (0,1). That seems like an easy and reasonable approach.

@mkborregaard
Copy link
Member

@JeffBezanson implemented as requested in #1900

@t-bltg
Copy link
Member

t-bltg commented Nov 24, 2022

Fixed.

@t-bltg t-bltg closed this as completed Nov 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants