Search code examples
juliamakie.jl

Colouring different datasets Algebra of Graphics (Julia)


I am using Algebra of Graphics to plot multiple datasets in the following way:

function filterPlot(filterPos)
    
    #filterPos - a vector of vectors 


     dataForPlot = data(DataFrame(xx = 1:length(filterPos[1]), yy = filterPos[1]))
        for thing in filterPos[2:end]
            plotFilter = DataFrame(xx = 1:length(thing), yy = thing)
            dataForPlot =dataForPlot + data(plotFilter)
        end

        
   
    
    dataForPlot *= mapping(:1=>(t->t) ,:2 => (t->t)); # data(toBePlotted)*mapping(:a =>(t->t) =>"Time (d)",:b => (t->t)=>"Weight")*linear();

    plaxis = (xlabel = xlab, ylabel = ylab)

    drawing = draw(dataForPlot;axis = plaxis,palettes=(; color=ColorSchemes.Set1_3.colors))
end

Note that filterPos can have arbitrary many data sets in it. Ideally I would like each one of them displayed in a separate colour (one that I do not need to set manually). I know matplotlib automatically colours things. Is there something like that in Makie or AlgebraofGraphics?


Solution

  • It looks like you are combining data by generating a bunch of individual DataFrame objects from each of the vectors passed to filterPlot, then summing them by effectively doing AlgebraOfGraphics.data(df1) + AlgebraOfGraphics.data(df2) + .... That works, but if you just want each of those DataFrames to have a different hue in your plot while applying the same mapping and visual to all of them, consider combining the DataFrames first along with a dummy variable that identifies the vector of origin.

    To do that, start by combining the vector of vectors into a long DataFrame:

    using DataFrames, CairoMakie, AlgebraOfGraphics
    
    # fake data: 5 vectors of random size containing lines of data with noise
    rand_line(slope, n) = slope .* (1:n) .+ randn(n)
    filterPos = [rand_line(slope, rand(10:20)) for slope in 1:5]
    
    # a function to convert a Vector to a DataFrame in the format you want
    vec_to_df((id, values)) = DataFrame(label = id, xx = 1:length(values), yy = values)
    
    # combine all the vectors by mapping our vec_to_df function to each and reducing with vcat
    df = mapreduce(vec_to_df, vcat, enumerate(filterPos))
    

    At this point, you can follow the example from the AlgebraOfGraphics documentation for the linear function:

    # plot, using the :label column as non-numeric to separate datasets
    draw(data(df) * mapping(:xx, :yy, color = :label => nonnumeric) * (linear() + visual(Scatter)))
    

    Result:

    A plot of points lying along five separate lines of different slopes, each with a different color