3

I'm trying to plot several related plots in a grid and I'd like to give a shared title. However, when I use plot(plot1, plot2, title="my title") Plots.jl titles each separate plot with that title. Is there a way to fix this?

I tested the code below with the gr() and plotly() backend. Both have the same behavior.

    using Plots
    using DataFrames

    gr()  # plotly() backend has the same behavior
    
    anscombes_quartet = DataFrame([
    10.0    8.04    10.0    9.14    10.0    7.46    8.0     6.58
    8.0     6.95    8.0     8.14    8.0     6.77    8.0     5.76
    13.0    7.58    13.0    8.74    13.0    12.74   8.0     7.71
    9.0     8.81    9.0     8.77    9.0     7.11    8.0     8.84
    11.0    8.33    11.0    9.26    11.0    7.81    8.0     8.47
    14.0    9.96    14.0    8.10    14.0    8.84    8.0     7.04
    6.0     7.24    6.0     6.13    6.0     6.08    8.0     5.25
    4.0     4.26    4.0     3.10    4.0     5.39    19.0    12.50
    12.0    10.84   12.0    9.13    12.0    8.15    8.0     5.56
    7.0     4.82    7.0     7.26    7.0     6.42    8.0     7.91
    5.0     5.68    5.0     4.74    5.0     5.73    8.0     |6.89 
    ])
    
    rename!(anscombes_quartet, ["x1", "y1", "x2", "y2", "x3", "y3", "x4", "y4"])
    
    plot(
        scatter(anscombes_quartet.x1, anscombes_quartet.y1, label=""),
        scatter(anscombes_quartet.x2, anscombes_quartet.y2, label=""),
        scatter(anscombes_quartet.x3, anscombes_quartet.y3, label=""),
        scatter(anscombes_quartet.x4, anscombes_quartet.y4, label=""),
        title = "Anscombes quartet"
    )

enter image description here

Jonas
  • 1,401
  • 9
  • 25

3 Answers3

1

I found a hacky solution, that uses an empty plot:

    using Plots: grid
    
    # make "title plot" really shallow
    l = @layout [
    a{0.001h}; grid(2,2)
    ]
    
    plot(
        plot(title="test", grid=false, showaxis = false, ticks = false),
        scatter(anscombes_quartet.x1, anscombes_quartet.y1, label=""),
        scatter(anscombes_quartet.x2, anscombes_quartet.y2, label=""),
        scatter(anscombes_quartet.x3, anscombes_quartet.y3, label=""),
        scatter(anscombes_quartet.x4, anscombes_quartet.y4, label=""),
        title = ["Anscombes quartet" "A"  "B"  "C"  "D"],
        titlelocation   = :left,
        titlefonthalign = :left,  # fixes plotly() text alignment
        layout = l
    )

enter image description here

One downside of this solution is that it doesn't allow you to adjust the "main title" separately since it's just another subtitle. For more info on the grid structure see the docs.

If somebody knows a better solution, please let me know and I'll gladly accept it instead of my own.

Jonas
  • 1,401
  • 9
  • 25
  • I found a slightly different approach [in this answer](https://stackoverflow.com/questions/43066957/adding-global-title-to-plots-jl-subplots?rq=1), that just adds a plot with text instead of an empty plot with a title. – Jonas Mar 17 '21 at 14:02
1

Not in Plots.jl but in PyPlot.jl

    using PyPlot
    
    figure, axis = PyPlot.subplots(2, 2, constrained_layout = true) 

    axis[1,1].scatter(anscombes_quartet.x1, anscombes_quartet.y1)
    axis[1,1].set_title("A", loc="left") 
    axis[1,2].scatter(anscombes_quartet.x2, anscombes_quartet.y2)
    axis[1,2].set_title("B", loc="left") 
    axis[2,1].scatter(anscombes_quartet.x3, anscombes_quartet.y3)
    axis[2,1].set_title("C", loc="left") 
    axis[2,2].scatter(anscombes_quartet.x4, anscombes_quartet.y4)
    axis[2,2].set_title("D", loc="left") 
    
    suptitle("Anscombes quartet")
    gcf()  # or show()

enter image description here

Jonas
  • 1,401
  • 9
  • 25
1

In more recent versions of Plots, this functionality is included in the plot_title keyword which this PR added to Plots v1.19. Documentation is still lacking, so here's an example with the original question:

using Plots #tested v1.29
using DataFrames #tested v1.3.4

gr()

anscombes_quartet = DataFrame([
10.0    8.04    10.0    9.14    10.0    7.46    8.0     6.58
8.0     6.95    8.0     8.14    8.0     6.77    8.0     5.76
13.0    7.58    13.0    8.74    13.0    12.74   8.0     7.71
9.0     8.81    9.0     8.77    9.0     7.11    8.0     8.84
11.0    8.33    11.0    9.26    11.0    7.81    8.0     8.47
14.0    9.96    14.0    8.10    14.0    8.84    8.0     7.04
6.0     7.24    6.0     6.13    6.0     6.08    8.0     5.25
4.0     4.26    4.0     3.10    4.0     5.39    19.0    12.50
12.0    10.84   12.0    9.13    12.0    8.15    8.0     5.56
7.0     4.82    7.0     7.26    7.0     6.42    8.0     7.91
5.0     5.68    5.0     4.74    5.0     5.73    8.0     6.89 
], :auto)

rename!(anscombes_quartet, ["x1", "y1", "x2", "y2", "x3", "y3", "x4", "y4"])

plot(
    scatter(anscombes_quartet.x1, anscombes_quartet.y1, label=""),
    scatter(anscombes_quartet.x2, anscombes_quartet.y2, label=""),
    scatter(anscombes_quartet.x3, anscombes_quartet.y3, label=""),
    scatter(anscombes_quartet.x4, anscombes_quartet.y4, label=""),
    plot_title = "Anscombes quartet"
)

Code Output:

Code Output

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
mrouleau
  • 19
  • 3