# Create plot with multiple colorgradients

**URL:** <https://discourse.julialang.org/t/create-plot-with-multiple-colorgradients/73383>\
**Category:** Visualization\
**Tags:** plots\
**Created:** [December 20, 2021, 4:44pm UTC](https://discourse.julialang.org/t/create-plot-with-multiple-colorgradients/73383 "2021-12-20T16:44:05Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![DrChainsaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drchainsaw/32/8497_2.png) [@DrChainsaw](https://discourse.julialang.org/u/DrChainsaw)\
**Post date:** [December 20, 2021, 4:44pm UTC](https://discourse.julialang.org/t/create-plot-with-multiple-colorgradients/73383/1 "2021-12-20T16:44:05Z")

</div>

I’m trying to visualize some data where I want to see some kind of distribution a (small) set of per sample distributions.

I doubt that the description makes much sense, but this MWE creates the type of figure I would like to see by just mapping values to a color manually to create an image:

```julia
using Plots
# This creates 21 samples with three sets of data in each sample
dummydata = [(0.1:0.1:x, 0.2:0.2:x, 0.3:0.3:x) for x in 0:0.05:1];

function colormatrix(pdata, cms)
           z = fill(colorant"white", length(pdata), maximum(x -> sum(length, x), pdata)+1)
           for (i, row) in enumerate(pdata)
               offs = 0
               for (cm, series) in zip(cms, row)
                   nelems = length(series)
                   nelems > 0 || continue
                   z[i, 1+offs:nelems+offs] .= cm[series]
                   offs += nelems
               end
           end
           return z
       end

plot(colormatrix(dummydata, (cgrad(:reds), cgrad(:blues), cgrad(:greens))))

```

The problem with the above approach is that I want to do this for a couple of million samples and the plot command either chokes or produces an invisibly thin horizontal line (as the x-axis has much fewer values than the y-axis).

If I instead make `z` an array of floats and let `plots.heatmap` handle the image generation I get something which looks good, but I can’t find a good way to separate the ranges of the colorgradient so the `series` will blend into each other.

I can ensure that each `series` (as used in `colormatrix`) lies within a distinct numeric range (e.g. first series in 0-1, second in 2-3 etc.) in case that can be helpful.

I also can’t find what trick `Plots.heatmap` uses to avoid the ‘too many pixels’ problem. Can one apply it to a matrix of `Color`s? I have tried using `aspect_ratio` set to `1` or `:equal` but it does not help (enough). Setting `size` does not help either.

I don’t have to use `Plots` for this btw, its just what I have tried so far.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [December 20, 2021, 5:10pm UTC](https://discourse.julialang.org/t/create-plot-with-multiple-colorgradients/73383/2 "2021-12-20T17:10:57Z")

</div>

Linking this related [GR example](https://heliosdrm.github.io/GRUtils.jl/stable/api/plotting/#Images), in case it is useful.

---

<div class="post-metadata">

**Author:** ![DrChainsaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drchainsaw/32/8497_2.png) [@DrChainsaw](https://discourse.julialang.org/u/DrChainsaw)\
**Post date:** [December 20, 2021, 5:57pm UTC](https://discourse.julialang.org/t/create-plot-with-multiple-colorgradients/73383/3 "2021-12-20T17:57:13Z")

</div>

Thanks, but I seem to get the same type of problem as with `Plots`. For example:

```julia
# Not even visible to me
GRUtils.imshow(rand(1000_000, 10))

# A very thin picture:
GRUtils.imshow(rand(1000, 10))

# This streches and blends/aliases the pixels somehow
Plots.heatmap(rand(1000_000, 10))

```

I guess the last example destroys data as my screen can’t show one million vertical pixels, but since I intend to plot sorted data that should not matter as one should be able to grasp the overall distribution.

Edit: What is missing from the last example is a way to control the colormap, e.g. so that `0:0.57` uses `cgrad(:reds)` and the rest uses `cgrad(:greens)`. I’m perfectly happy with pixels being merged/aliased (whatever the term is) for the `1e6` sized dimension and stretched out for the small sized dimension.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [December 20, 2021, 6:14pm UTC](https://discourse.julialang.org/t/create-plot-with-multiple-colorgradients/73383/4 "2021-12-20T18:14:52Z")

</div>

You may want to play with the 4th channel (RGBA alpha transparency) for blending?

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [December 20, 2021, 6:24pm UTC](https://discourse.julialang.org/t/create-plot-with-multiple-colorgradients/73383/5 "2021-12-20T18:24:36Z")

</div>

This [other post](https://discourse.julialang.org/t/is-there-a-way-to-do-digital-phosphor-type-of-plots-for-time-series-data/56490/12) takes a different approach, uses a single color scheme, but might be of interest, just in case.

---

<div class="post-metadata">

**Author:** ![DrChainsaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drchainsaw/32/8497_2.png) [@DrChainsaw](https://discourse.julialang.org/u/DrChainsaw)\
**Post date:** [December 20, 2021, 6:28pm UTC](https://discourse.julialang.org/t/create-plot-with-multiple-colorgradients/73383/6 "2021-12-20T18:28:56Z")

</div>

> You may want to play with the 4th channel (RGBA alpha transparency) for blending?

As in making separate calls to `heatmap!` for each colormap and line them up? I was thinking of this, but is there a way to do this with numerical input? I’m also a bit concerned with performance as things need to run N times instead of 1. It already takes almost a minute to draw/display the image.

I suppose a hacky way could be to use a sentinel value for a fully transparent `RGBA` which is manually concatenated with the desired colormap (not sure how to do this, but I assume it is possible somehow). Is there a way to use `NaN` for this sentinel value?

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [December 20, 2021, 6:45pm UTC](https://discourse.julialang.org/t/create-plot-with-multiple-colorgradients/73383/7 "2021-12-20T18:45:31Z")

</div>

I was thinking about one single plot call. We would map first the millions of dots onto a big RGBA matrix, where 3 data families would live in separate R, G, B channels and they would blend via alpha. But I might be wrong.

---

<div class="post-metadata">

**Author:** ![DrChainsaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drchainsaw/32/8497_2.png) [@DrChainsaw](https://discourse.julialang.org/u/DrChainsaw)\
**Post date:** [December 20, 2021, 6:56pm UTC](https://discourse.julialang.org/t/create-plot-with-multiple-colorgradients/73383/8 "2021-12-20T18:56:02Z")

</div>

> map first the millions of dots into a big RGBA matrix

The problem with an `RGB(A)` matrix seems to be that pixels are not blended automatically when trying to display the image.

I have no idea what algorithm blends/stretches the pixels when `Plots.heatmap(rand(1000_000, 10))` is called but it seems to do a pretty good job in my case.

I tried the following naive implementation of the overlapping figures approach, but it seems to be too slow (has been running for about 5 minutes now with 200k rows dummydata):

```julia
function colorplot(pdata, cms)
    plt = heatmap()
    for (i, row) in enumerate(pdata)
        offs = 0
        for (cm, series) in zip(cms, row)
            nelems = length(series)
            nelems > 0 || continue
            heatmap!(plt, 1+offs:nelems+offs, i:i, permutedims(series)'; c=cm)
            offs += nelems
        end
    end
    return plt
end

```

---

<div class="post-metadata">

**Author:** ![DrChainsaw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drchainsaw/32/8497_2.png) [@DrChainsaw](https://discourse.julialang.org/u/DrChainsaw)\
**Post date:** [December 20, 2021, 7:11pm UTC](https://discourse.julialang.org/t/create-plot-with-multiple-colorgradients/73383/9 "2021-12-20T19:11:02Z")

</div>

Ok, this less naive version seems to be much faster:

```julia
function colorplot(pdata, cms)
    zs = ntuple(_ -> fill(NaN, length(pdata), maximum(r -> sum(length, r), pdata)), length(cms))
    for (i, row) in enumerate(pdata)
        offs = 0
        for (z, series) in zip(zs, row)
            nelems = length(series)
            nelems > 0 || continue
            z[i, 1+offs:nelems+offs] = series
            offs += nelems
        end
    end
    plt = plot()
    for (z, cm) in zip(zs, cms)
        heatmap!(plt, z; c=cm)
    end
    return plt
end

```

I’ll use it for now unless someone has a better way.
