Search code examples
juliaplotly.js

Contour plot of boolean data using PlotlyJS in julia


I have an array of boolean data like, e.g.,

z = [true true true 
true false true 
true true true]

I want to make a contour plot of this data, which in this case should just be a 3x3 grid where the central cell is indicated by a line. I tried

using PlotlyJS

z = [true true true 
    true false true 
    true true true]
x = range(1,3)
y = range(1,3)

plt = contour(
    x = x,
    y = y,
    z = Int.(.!z),
    contours_coloring = "lines",
    contours_start = 0,
    contours_end = 1,
    contours_size = 1,
    colorscale = [[0, "black"], [1, "black"]],
    line_smoothing = 0,
    line_width = 3,
    zmin = 0,
    zmax = 1,
    showscale = false,
)
plot(plt)

But this only produces

enter image description here

Is there some way to create a plot that just marks the central cell?


Solution

  • Without knowing your scenario, it would seem that a heatmap is likely to be a better format than a contour. I say this because your question is implicitly treating data points as data bins. You are asking if there is a way to contour the bins in which points lie. While not composed of contour lines, a heatmap may be clearest way to communicate that you are dealing with bins and not lines. Below is a simple implementation.

    using PlotlyJS
    
    z = [true true true 
        true false true 
        true true true]
    
    plt = PlotlyJS.heatmap(
        x = range(1,size(z)[1]),
        y = range(1,size(z)[2]),
        z = Int.(.!z),
        colorsca
    )
    PlotlyJS.plot(plt)
    
    

    But, assuming is not commonly the best approach, so here is a way to create this type of contour plot. To do this, we need to make a mapping of points to bins. For example, anything where 0.5<x<1.5 and 0.5<y<1.5 need to fetch the value of z[1,1]. Then, we can make a contour plot, and (with enough datapoints), the contour will follow around cells.

    In the following, I used Plots.jl, but

    using PlotlyJS
    
    zRef = [true true true 
        true false true 
        true true true]
    
    # creating our mapping function
    function fetchReferenceVal(ref::Matrix, xs::Vector{<:Real},ys::Vector{<:Real})
        # initializing an empty output
        # depending on your scenario, the filling value may need to be changed.
        out = fill(1,length(xs),length(ys))
        
        # are x and y going to lie in our matrix?
        for (i,x) in enumerate(xs)
            !(x >=1 && x <= size(ref)[1]) && continue
            for (j,y) in enumerate(ys)
                !(y >= 1 && y<= size(ref)[2]) && continue
    
                # ... Fetch associated value
                out[i,j] = Int(ref[Int(round(x)),Int(round(y))])
            end
        end
        return out
    end
    
    x = [i for i in 0:.01:4]
    y = [i for i in 0:.01:4]
    z = fetchReferenceVal(zRef, x, y)
    
    plt = PlotlyJS.contour(
        x = x,
        y = y,
        z = z,
        contours_coloring = "lines",
        contours_start = 0,
        contours_end = 1,
        contours_size = 1,
        colorscale = [[0, "black"], [1, "black"]],
        line_smoothing = 0,
        line_width = 3,
        zmin = 0,
        zmax = 1,
        showscale = false,
    )
    PlotlyJS.plot(plt)
    

    contour plot