# How to plot a simple stacked area chart

All I need to do is to plot a simple stacked chart (possibly also normalised).

I would like to start from these simple data:

``````a = [1,1,1,1.5,2,3]
b = [0.5,0.6,0.4,0.3,0.3,0.2]
c = [2,1.8,2.2,3.3,2.5,1.8]
sNames = ["a","b","c"]
xLabels = [2001,2002,2003,2004,2005,2006]
`````` I did try:

• PlotRecipes (now “GraphRecipes”) but the example given is too complex and it doesn’t run on Julia 1.1
• Vega.jl. The example seems simple enought, but the package doesn’t work on Julia >= 0.7
• VegaLite.jl. The example is very complex too, and I didn’t manage to reduce it to my simpler case
• groupedbar recipe of StatsPlots, but it’s a histogram not a stacked area chart, and it is not indicated how to get it normalised (aside of course manually doing that ex-ante)

I have to say I’m a bit frustrated… I may just be dumb, I feel like in the domain of plotting there is a competition on showing cool features you can get with the various plotting packages, instead of showing simple examples that highlight one specific point at the time…

Here’s one way:

``````using Plots

@userplot StackedArea

# a simple "recipe" for Plots.jl to get stacked area plots
# usage: stackedarea(xvector, datamatrix, plotsoptions)
@recipe function f(pc::StackedArea)
x, y = pc.args
n = length(x)
y = cumsum(y, dims=2)
seriestype := :shape

# create a filled polygon for each item
for c=1:size(y,2)
sx = vcat(x, reverse(x))
sy = vcat(y[:,c], c==1 ? zeros(n) : reverse(y[:,c-1]))
@series (sx, sy)
end
end

a = [1,1,1,1.5,2,3]
b = [0.5,0.6,0.4,0.3,0.3,0.2]
c = [2,1.8,2.2,3.3,2.5,1.8]
sNames = ["a","b","c"]
x = [2001,2002,2003,2004,2005,2006]

plotly()
stackedarea(x, [a b c], labels=reshape(sNames, (1,3)))
`````` 1 Like

Thank you… I guess that if I want a “normalise” option I need to change the logic inside that function… but how to pass it a further, non-plots parameter ? like this?:

``````@recipe function f(pc::StackedArea; normalise=false)
[...]
``````

The trick for VegaLite.jl (and presumably any grammar of graphics like package) is that you first need to get your data into a tidy format, and then can plot it.

If I start out putting this into a `DataFrame`:

``````using DataFrames

a = [1,1,1,1.5,2,3]
b = [0.5,0.6,0.4,0.3,0.3,0.2]
c = [2,1.8,2.2,3.3,2.5,1.8]
sNames = ["a","b","c"]
xLabels = [2001,2002,2003,2004,2005,2006]

df = DataFrame(year=xLabels, a=a, b=b, c=c)
``````

then one can put it into tidy format easily with `stack`:

``````julia> df |> stack
18×3 DataFrame
│ Row │ variable │ value   │ year  │
│     │ Symbol   │ Float64 │ Int64 │
├─────┼──────────┼─────────┼───────┤
│ 1   │ a        │ 1.0     │ 2001  │
│ 2   │ a        │ 1.0     │ 2002  │
│ 3   │ a        │ 1.0     │ 2003  │
│ 4   │ a        │ 1.5     │ 2004  │
│ 5   │ a        │ 2.0     │ 2005  │
│ 6   │ a        │ 3.0     │ 2006  │
│ 7   │ b        │ 0.5     │ 2001  │
│ 8   │ b        │ 0.6     │ 2002  │
│ 9   │ b        │ 0.4     │ 2003  │
│ 10  │ b        │ 0.3     │ 2004  │
│ 11  │ b        │ 0.3     │ 2005  │
│ 12  │ b        │ 0.2     │ 2006  │
│ 13  │ c        │ 2.0     │ 2001  │
│ 14  │ c        │ 1.8     │ 2002  │
│ 15  │ c        │ 2.2     │ 2003  │
│ 16  │ c        │ 3.3     │ 2004  │
│ 17  │ c        │ 2.5     │ 2005  │
│ 18  │ c        │ 1.8     │ 2006  │
``````

From there on it is pretty simple with VegaLite.jl. Here is the base version:

``````df |>
stack |>
@vlplot(:area, x=:year, y={:value, stack=:zero}, color="variable:n")
``````

That gives me: And normalized:

``````df |>
stack |>
@vlplot(:area, x=:year, y={:value, stack=:normalize}, color="variable:n")
``````

looks like this: 4 Likes

Plots.jl now ships with the `areaplot` command.

4 Likes

Does anyone know how to make a recipe for a stacked area plot so that the PlotlyJS backend behavior resembles the figure created by the following code?

``````using PlotlyJS
function area()
traces = [PlotlyJS.scatter(;x=1:3, y=[2, 1, 4], fill="tonexty", stackgroup = "one",),
PlotlyJS.scatter(;x=1:3, y=[1, 1, 2], fill="tonexty", stackgroup = "one",),
PlotlyJS.scatter(;x=1:3, y=[3, 0, 2], fill="tonexty", stackgroup = "one",)]

PlotlyJS.plot(traces, PlotlyJS.Layout(title="stacked and filled line chart"))
end
area()
``````