3
$\begingroup$

I'd like to align the elements of the PlotLegend in a single horizontal row beneath the TimelinePlot, as there is plenty of room for that (especially when I adjust the Size to be large). Instead the internal algorithms pack the PlotLegends into three rows in this case.

How to fix that?

TimelinePlot[
 {

  <|{Entity["Person", "LeonardoDaVinci::47w36"] -> 
     Interval[{"1452", "1521"}]
    }|>,

  <|{Entity["Person", "CamilleCorot::vx57d"] -> 
     Interval[{"1796", "1875"}]
    }|>,

  <|{
    "Piet Mondrian" -> Interval[{"1872", "1944"}]
    }|>,

  <|{"Thomas Gainsborough" -> Interval[{"1727", "1788"}]
    }|>,

  <|{Entity["Person", "JanDavidszDeHeem::2gt75"] -> 
     Interval[{"1606", "1684"}]
    }|>,

  <|{"Pablo Picasso" -> Interval[{"1881", "1973"}]
    }|>,

  <|{"Hokusai" -> Interval[{"1760", "1849"}]
    }|>

  }
 ,
 PlotStyle -> {Red, Orange, Darker[Yellow], Green, Blue, Purple, 
   Black},
 PlotLegends -> 
  Placed[{Text[Style["Italian", 16, Italic, FontFamily -> "Times"]],
    Text[Style["French", 16, Italic, FontFamily -> "Times"]],
    Text[Style["American", 16, Italic, FontFamily -> "Times"]],
    Text[Style["British", 16, Italic, FontFamily -> "Times"]],
    Text[Style["Flemish", 16, Italic, FontFamily -> "Times"]],
    Text[Style["Spanish", 16, Italic, FontFamily -> "Times"]],
    Text[Style["Japanese", 16, Italic, FontFamily -> "Times"]]}, 
   Below],
 AspectRatio -> 1/2,
 PlotLayout -> "Packed",
 Background -> LightGray,
 ImageSize -> 600,
 AxesOrigin -> Center]

enter image description here

$\endgroup$
  • 1
    $\begingroup$ If the legend is to indicate nationality, then it should be „Dutch“ for de Heem. Also the curator of knowledge in the WL should be told that „Davidsz.“ is an abbreviation for „Davidszoon“ - so there is a period missing. $\endgroup$ – gwr Mar 20 at 13:11
4
$\begingroup$

You can do this by Legendeding the plot itself and then using LegendLayout:

tlp = TimelinePlot[{<|{Entity["Person", "LeonardoDaVinci::47w36"] -> 
      Interval[{"1452", "1521"}]}|>, <|{Entity["Person", 
       "CamilleCorot::vx57d"] -> 
      Interval[{"1796", "1875"}]}|>, <|{"Piet Mondrian" -> 
      Interval[{"1872", "1944"}]}|>, <|{"Thomas Gainsborough" -> 
      Interval[{"1727", "1788"}]}|>, <|{Entity["Person", 
       "JanDavidszDeHeem::2gt75"] -> 
      Interval[{"1606", "1684"}]}|>, <|{"Pablo Picasso" -> 
      Interval[{"1881", "1973"}]}|>, <|{"Hokusai" -> 
      Interval[{"1760", "1849"}]}|>}, 
  PlotStyle -> {Red, Orange, Darker[Yellow], Green, Blue, Purple, 
    Black}, AspectRatio -> 1/2, PlotLayout -> "Packed", 
  Background -> LightGray, ImageSize -> 600, AxesOrigin -> Center]

Now we add our legend. Note the LegendLayout function:

Legended[tlp,
 Placed[
  LineLegend[{Red, Orange, Darker[Yellow], Green, Blue, Purple, Black},
   {"Italian", 
     "French", "American", "British", "Flemish", "Spanish", 
     "Japanese"}, 
   LabelStyle -> {16, Italic, FontFamily -> "Times"},
   LegendLayout -> (Row[Row[#, Spacer[1]] & /@ #, Spacer[7]] &), 
   LegendMargins -> 0], Below]]

Resulting in:

enter image description here

I'm sure there's a more elegant way to do this than creating nested Rows, but I'm afraid I don't have the time to have a look.

$\endgroup$
4
$\begingroup$

Just a slightly different take for readability avoiding Slot, using Riffle for the Spacers and constructing the graphics with centralized components (e.g. using With):

With[
  { data = 
       { <|{Entity["Person", "LeonardoDaVinci::47w36"] -> Interval[{"1452", "1521"}]}|>
       , <|{Entity["Person", "CamilleCorot::vx57d"] -> Interval[{"1796", "1875"}]}|>
       , <|{"Piet Mondrian" -> Interval[{"1872", "1944"}]}|>
       , <|{"Thomas Gainsborough" -> Interval[{"1727", "1788"}]}|>
       , <|{Entity["Person", "JanDavidszDeHeem::2gt75"] -> Interval[{"1606", "1684"}]}|>
       , <|{"Pablo Picasso" -> Interval[{"1881", "1973"}]}|>
       , <|{"Hokusai" -> Interval[{"1760", "1849"}]}|>
       }
  , colors = { Red, Orange, Darker[Yellow], Green, Blue, Purple, Black }
  , styleFunc = Function[ text, 
       Style[ text, 16, Italic, FontFamily -> "Times"]
    ]
  , labels = { "Italian", "French", "American", "British", "Flemish", "Spanish", "Japanese" }
  , layoutFunc = Function[ pairs, (* pairs = { {col1, lbl1}, ... } *)
       pairs // RightComposition[
          Flatten
          , Curry[Riffle][{Spacer[2] (* after color *), Spacer[10] (* between labels *) }] 
          , Row
       ]
    ]
  }
  ,
  TimelinePlot[ data
    , PlotStyle -> colors
    , AxesOrigin -> Center
    , AspectRatio -> 1/2
    , PlotLegends -> Curry[Placed][Bottom] @ LineLegend[
         colors,
         styleFunc /@ labels
         , LegendLayout -> layoutFunc
         , LegendMargins -> 0
      ] 
    , PlotLayout -> "Packed"
    , Background -> LightGray
    , ImageSize -> 600
  ]
]

TimelinePlot

$\endgroup$
  • $\begingroup$ That's really interesting, it didn't occur to me that you could use currying in this way! $\endgroup$ – Carl Lange Mar 20 at 13:24
4
$\begingroup$

Per this answer, you can use the option LegendLayout -> {"Row", 1}.

data = {<|{Entity["Person", "LeonardoDaVinci::47w36"] -> 
     Interval[{"1452", "1521"}]}|>, <|{Entity["Person", 
      "CamilleCorot::vx57d"] -> 
     Interval[{"1796", "1875"}]}|>, <|{"Piet Mondrian" -> 
     Interval[{"1872", "1944"}]}|>, <|{"Thomas Gainsborough" -> 
     Interval[{"1727", "1788"}]}|>, <|{Entity["Person", 
      "JanDavidszDeHeem::2gt75"] -> 
     Interval[{"1606", "1684"}]}|>, <|{"Pablo Picasso" -> 
     Interval[{"1881", "1973"}]}|>, <|{"Hokusai" -> 
     Interval[{"1760", "1849"}]}|>};

labels = {Text[
      Style["Italian", 16, Italic, FontFamily -> "Times"]], 
     Text[Style["French", 16, Italic, FontFamily -> "Times"]], 
     Text[Style["American", 16, Italic, FontFamily -> "Times"]], 
     Text[Style["British", 16, Italic, FontFamily -> "Times"]], 
     Text[Style["Flemish", 16, Italic, FontFamily -> "Times"]], 
     Text[Style["Spanish", 16, Italic, FontFamily -> "Times"]], 
     Text[Style["Japanese", 16, Italic, FontFamily -> "Times"]]};

TimelinePlot[data, 
  PlotStyle -> {Red, Orange, Darker[Yellow], Green, Blue, Purple, Black}, 
  PlotLegends -> Placed[LineLegend[labels, LegendLayout -> {"Row", 1}], Below], 
  AspectRatio -> 1/2, 
  PlotLayout -> "Packed", 
  Background -> LightGray, 
  ImageSize -> 600, 
  AxesOrigin -> Center
]

enter image description here

$\endgroup$
  • $\begingroup$ Cool (+1). So, they had 6 years to finally document this ... and did not? $\endgroup$ – gwr Mar 20 at 13:31
  • $\begingroup$ That appears to be the case. $\endgroup$ – Chip Hurst Mar 20 at 13:38
  • $\begingroup$ Aha, this is the real solution! I can't believe this is undocumented. I also have a hard time understanding why they used "Row" the string rather than Row the symbol... $\endgroup$ – Carl Lange Mar 20 at 13:59
  • 1
    $\begingroup$ My guess is the string version maintains consistency among other choices like "ReversedRow", etc. In addition, LegendLayout allows for an arbitrary function f and so parsing Row in this way would create ambiguity. $\endgroup$ – Chip Hurst Mar 20 at 14:02
  • 3
    $\begingroup$ Since LineLegend accepts a LabelStyle option, you could simplify things by using LineLegend[labels, LegendLayout -> {"Row", 1}, LabelStyle -> {16, Italic, FontFamily -> "Times"}] and dropping all of those Style/Text wrappers in the labels. $\endgroup$ – Carl Woll Mar 20 at 16:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.