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 '19 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.

| improve this answer | |
$\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

| improve this answer | |
$\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 '19 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

| improve this answer | |
$\endgroup$
  • $\begingroup$ Cool (+1). So, they had 6 years to finally document this ... and did not? $\endgroup$ – gwr Mar 20 '19 at 13:31
  • $\begingroup$ That appears to be the case. $\endgroup$ – Chip Hurst Mar 20 '19 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 '19 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 '19 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 '19 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.