-
Notifications
You must be signed in to change notification settings - Fork 2
/
legend.ex
127 lines (102 loc) · 3.84 KB
/
legend.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
defmodule Tucan.Legend do
@moduledoc """
Helper utilities for configuring the plot legend.
"""
alias Tucan.Utils
@legend_channels [:color, :size, :shape]
@doc """
Sets the title of the given legend.
You can optionally pass any title option supported by vega-lite to customize the
style of it.
Applicable only on plots with a legend.
## Examples
```tucan
Tucan.scatter(:iris, "petal_width", "petal_length", color_by: "species")
|> Tucan.Legend.set_title(:color, "Iris Species", title_color: "red", title_font_weight: 300)
```
"""
@spec set_title(
vl :: VegaLite.t(),
channel :: atom(),
title :: String.t() | nil,
opts :: keyword()
) :: VegaLite.t()
def set_title(vl, channel, title, opts \\ [])
when is_struct(vl, VegaLite) and is_atom(channel) and is_list(opts) do
title_opts = Keyword.merge(opts, title: title)
put_legend_options(vl, channel, title_opts, "set_title/4")
end
@legend_orientations ~w(left right top bottom top-left top-right bottom-left bottom-right none)
@doc """
Sets the legend orientation with respect to the scene.
You need to define the `channel` for which the legend will be configured. Orientation
can be one of the following: `#{inspect(@legend_orientations)}`.
Applicable only on plots with a legend.
## Examples
```tucan
Tucan.scatter(:iris, "petal_width", "petal_length")
|> Tucan.color_by("species")
|> Tucan.shape_by("species")
|> Tucan.Legend.set_orientation(:color, "bottom")
|> Tucan.Legend.set_orientation(:shape, "top")
```
"""
@spec set_orientation(vl :: VegaLite.t(), channel :: atom(), orientation :: String.t()) ::
VegaLite.t()
def set_orientation(vl, channel, orientation)
when is_struct(vl, VegaLite) and is_atom(channel) and is_binary(orientation) do
validate_inclusion!(orientation, @legend_orientations, "invalid legend orientation")
put_legend_options(vl, channel, [orient: orientation], "set_orientation/3")
end
@doc """
Enables or disables the legend of the given encoding channel.
"""
@spec set_enabled(vl :: VegaLite.t(), channel :: atom(), enabled :: boolean()) :: VegaLite.t()
def set_enabled(vl, channel, enabled) do
if enabled do
vl
else
Utils.put_encoding_options(vl, channel, legend: nil)
end
end
@doc """
Sets the offset in pixels by which to displace the legend from the data rectangle
and axes.
If not set defaults to 18 pixels.
## Examples
```tucan
Tucan.scatter(:iris, "petal_width", "petal_length")
|> Tucan.color_by("species")
|> Tucan.Legend.set_offset(:color, 5)
```
"""
@spec set_offset(vl :: VegaLite.t(), channel :: atom(), offset :: integer()) :: VegaLite.t()
def set_offset(vl, channel, offset) do
put_legend_options(vl, channel, [offset: offset], "set_offset/3")
end
@doc """
Set arbitrary options to the legend of the given channel.
The options are deep merged with existing options.
## Examples
```tucan
Tucan.scatter(:iris, "petal_width", "petal_length")
|> Tucan.color_by("species")
|> Tucan.Legend.put_options(:color, fill_color: "yellow", offset: 5, padding: 2, label_font_size: 14)
```
"""
@spec put_options(vl :: VegaLite.t(), channel :: atom(), opts :: keyword()) :: VegaLite.t()
def put_options(vl, channel, opts)
when is_struct(vl, VegaLite) and is_atom(channel) and is_list(opts) do
put_legend_options(vl, channel, opts, "put_legend_options/3")
end
defp put_legend_options(vl, channel, opts, caller) do
validate_inclusion!(channel, @legend_channels, "#{caller}: invalid legend channel")
Utils.put_encoding_options(vl, channel, legend: opts)
end
defp validate_inclusion!(value, allowed, message) do
if value not in allowed do
raise ArgumentError, "#{message}, allowed: #{inspect(allowed)}, got: #{inspect(value)}"
end
:ok
end
end