# Creating a plot containing subplots called from a function

**URL:** https://discourse.julialang.org/t/creating-a-plot-containing-subplots-called-from-a-function/107405
**Category:** General Usage
**Tags:** plotting
**Created:** [December 11, 2023, 2:28am UTC](https://discourse.julialang.org/t/creating-a-plot-containing-subplots-called-from-a-function/107405 "2023-12-11T02:28:35Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![evilrho](https://avatars.discourse-cdn.com/v4/letter/e/ba9def/32.png) [@evilrho](https://discourse.julialang.org/u/evilrho)
#### Post date: [December 11, 2023, 2:28am UTC](https://discourse.julialang.org/t/creating-a-plot-containing-subplots-called-from-a-function/107405/1 "2023-12-11T02:28:35Z")

</div>

Question about plotting, plot handles, subplots, etc. I’m trying to make a plot function that accepts a vector of a custom data structure. For each entry in the vector, another plot function is called which plots an individual element of the custom type. This function arrangement must be preserved since I need to have a separate individual element version of the function.

I’ve created a simplified version of this arrangement shown below, which does not currently work as expected, and only produces an empty plot. If I run ‘display(current())’, a plot of the last vector element shows up. Any help would be greatly appreciated. Thanks in advance.

```julia
using Plots

# Create a custom data struct
Base.@kwdef mutable struct CustType
    x::Vector{Float64} = 1:10
    y::Vector{Float64} = randn(10)
    z::Vector{Float64} = randn(10)
end

# Plot a single element of CustType in two subplots
function Plots.plot!(v::CustType; kwargs...)
    sub1 = Plots.plot(v.x,v.y)
    sub2 = Plots.plot(v.x,v.z)
    ph = Plots.plot!(sub1,sub2)
    return ph
end

# Create a plot consisting of two subplots from a vector of CustType
function Plots.plot(nt::Vector{CustType};kwargs...)
    plotly()
    ph = Plots.plot()
    for v in nt 
        Plots.plot!(v)
    end
    return ph
end

# Test the above code ...
ct_vec = fill(CustType(),5)
Plots.plot(ct_vec)

```

---

<div class="post-metadata">

### Author: ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)
#### Post date: [December 11, 2023, 3:08am UTC](https://discourse.julialang.org/t/creating-a-plot-containing-subplots-called-from-a-function/107405/2 "2023-12-11T03:08:57Z")

</div>

First of all, it would be better not to use `Plots.plot` to define your own methods, but instead, use a new name or [plot recipes](https://docs.juliaplots.org/latest/recipes/) to define your custom plots.

I don’t use Plots.jl a lot these days, but it seems that you should combine plots with the `Plots.plot(..., layout=...)` as described here [Tutorial · Plots](https://docs.juliaplots.org/latest/tutorial/#Combining-Multiple-Plots-as-Subplots).

In your current version, it is unclear how to add the `sub1, sub2` to the existing plot… I think what happens is that it adds `sub1, sub2` to the last current plot, which is in this setting `sub2` (as that was the last time the `Plots.plot(...)` command was called.

---

<div class="post-metadata">

### Author: ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)
#### Post date: [December 11, 2023, 3:16am UTC](https://discourse.julialang.org/t/creating-a-plot-containing-subplots-called-from-a-function/107405/3 "2023-12-11T03:16:51Z")

</div>

To solve the general problem, you implementation could maybe be done like this:

```julia
plot_xyz(v) = plot(v.x, [v.y v.z], layout = (1,2) )

ct_vec = fill(CustType(), 5)
plts = plot_xyz.(ct_vec)
plot(plts..., layout = (length(ct_vec, 1) )

```

Even better is maybe to deal with the layout of all plots in the end, such that the scales are better:

```julia
plot_xyz(v) = plot(v.x, v.y), plot(v.x, v.z)
plts = plot_xyz.(ct_vec)

plot(stack(plts)..., layout = (5,2) )

```

---

<div class="post-metadata">

### Author: ![evilrho](https://avatars.discourse-cdn.com/v4/letter/e/ba9def/32.png) [@evilrho](https://discourse.julialang.org/u/evilrho)
#### Post date: [December 11, 2023, 4:29am UTC](https://discourse.julialang.org/t/creating-a-plot-containing-subplots-called-from-a-function/107405/4 "2023-12-11T04:29:15Z")

</div>

Thanks for the help. Unfortunately, I have to keep the subplots, layout, etc. in the lower-level plot function so that it can stand on its own to generate a plot of a single element of CustType in a different part of the code.

It’s hard to see why this wouldn’t be possible with the correct handing of plot handles, etc. Maybe a different plotting package or backend might be better?

---

<div class="post-metadata">

### Author: ![SteffenPL](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/steffenpl/32/206270_2.png) [@SteffenPL](https://discourse.julialang.org/u/SteffenPL)
#### Post date: [December 11, 2023, 9:54am UTC](https://discourse.julialang.org/t/creating-a-plot-containing-subplots-called-from-a-function/107405/5 "2023-12-11T09:54:11Z")

</div>

> [@evilrho](#):
>
> Unfortunately, I have to keep the subplots, layout, etc. in the lower-level plot function so that it can stand on its own to generate a plot of a single element of CustType in a different part of the code.

In that case, you could do it as in the first example. E.g., produce one plot for the custom datatype and then combine all of them by putting them together into a column.

> [@evilrho](#):
>
> It’s hard to see why this wouldn’t be possible with the correct handing of plot handles, etc. Maybe a different plotting package or backend might be better?

I think it is possible, but you must provide the `layout` information to the `plot` functions, as the plotting package cannot guess how you want to arrange the plots in a layout (e.g. do you want rows, columns etc…).

> [@evilrho](#):
>
> Maybe a different plotting package or backend might be better?

Makie.jl has a very modern layout system (probably one of the best). But what you want to archive is also doable in Plots.jl.

---

<div class="post-metadata">

### Author: ![evilrho](https://avatars.discourse-cdn.com/v4/letter/e/ba9def/32.png) [@evilrho](https://discourse.julialang.org/u/evilrho)
#### Post date: [December 11, 2023, 4:42pm UTC](https://discourse.julialang.org/t/creating-a-plot-containing-subplots-called-from-a-function/107405/6 "2023-12-11T16:42:39Z")

</div>

So in regards to the layout, that is all set up in the lower level plot function. The actual function in my code is a little more complicated, and does indeed define the layout pattern. It is as follows:

```julia
ph = Plots.plot!(p1...,p2...,p3...,p4..., p5..., layout=(5,n),size=(1000,800))

```

p1 … p5 are plot handles similar to the simplified sub1, sub2 in my simplified example. As I said, this lower level plot function works well when called directly in other parts of our code. I just need to be able to call if from the higher level plot function when I have a vector of data I wish to plot.

Your suggestion above about combining the plot call into one single call:

```julia
plot_xyz(v) = plot(v.x, [v.y v.z], layout = (1,2) )

```

runs, but does not produce subplots. Instead, I get a single plot with two lines and 10 labels (y1…y10) shown in the legend.

Thanks for your help!

---

<div class="post-metadata">

### Author: ![evilrho](https://avatars.discourse-cdn.com/v4/letter/e/ba9def/32.png) [@evilrho](https://discourse.julialang.org/u/evilrho)
#### Post date: [December 11, 2023, 7:22pm UTC](https://discourse.julialang.org/t/creating-a-plot-containing-subplots-called-from-a-function/107405/7 "2023-12-11T19:22:10Z")

</div>

So after more experimentation, I found the following code to work:

```julia
using Plots

# Create a custom data struct
Base.@kwdef mutable struct CustType
    x::Vector{Float64} = 1:10
    y::Vector{Float64} = randn(10)
    z::Vector{Float64} = randn(10)
end

# Plot a single element of CustType in two subplots
function Plots.plot!(v::CustType; kwargs...)
    ph = Plots.current() 
    if ph.n == 0
        ph = Plots.plot(layout = (1,2))
    end
    Plots.plot!(ph.subplots[1],v.x,v.y; merge(kwargs,Dict(:label=>false))...)
    Plots.plot!(ph.subplots[2],v.x,v.z; kwargs...)
    return ph
end

# Create a plot consisting of two subplots from a vector of CustType
function Plots.plot(nt::Vector{CustType};kwargs...)
    plotly()
    Plots.plot()
    for (i,v) in enumerate(nt) 
        Plots.plot!(v, label="Run $(i)")
    end
    return current()
end

# Test the above code ...
ct_vec = [CustType() for _ in 1:5]
ph = Plots.plot(ct_vec)
display(ph)

```

If there’s a better way to get this to fit within the overall structure, I’d love to know. Thanks for the help!
