diff --git a/lib/exgboost/plotting.ex b/lib/exgboost/plotting.ex index e38679a..05a147a 100644 --- a/lib/exgboost/plotting.ex +++ b/lib/exgboost/plotting.ex @@ -1,60 +1,397 @@ defmodule EXGBoost.Plotting do - @moduledoc """ - Functions for plotting EXGBoost `Booster` models using [Vega](https://vega.github.io/vega/) + use EXGBoost.Plotting.Style - Fundamentally, all this module does is convert a `Booster` into a format that can be - ingested by Vega, and apply some default configuations that only account for a subset of the configurations - that can be set by a Vega spec directly. The functions provided in this module are designed to have opinionated - defaults that can be used to quickly visualize a model, but the full power of Vega is available by using the - `to_tabular/1` function to convert the model into a tabular format, and then using the `to_vega/2` function - to convert the tabular format into a Vega specification. + @doc """ + A light theme based on the [Solarized](https://ethanschoonover.com/solarized/) color palette + """ + style :solarized_light do + [ + # base3 + background: "#fdf6e3", + leaves: [ + # base01 + text: [fill: "#586e75", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + # base2, base1 + rect: [fill: "#eee8d5", stroke: "#93a1a1", strokeWidth: 1] + ], + splits: [ + # base01 + text: [fill: "#586e75", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + # base1, base00 + rect: [fill: "#93a1a1", stroke: "#657b83", strokeWidth: 1], + # base00 + children: [fill: "#657b83", stroke: "#657b83", strokeWidth: 1] + ], + yes: [ + # green + text: [fill: "#859900"], + # base00 + path: [stroke: "#657b83", strokeWidth: 1] + ], + no: [ + # red + text: [fill: "#dc322f"], + # base00 + path: [stroke: "#657b83", strokeWidth: 1] + ] + ] + end - ## Default Vega Specification + @doc """ + A dark theme based on the [Solarized](https://ethanschoonover.com/solarized/) color palette + """ + style :solarized_dark do + # base03 + [ + background: "#002b36", + leaves: [ + # base0 + text: [fill: "#839496", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + # base02, base01 + rect: [fill: "#073642", stroke: "#586e75", strokeWidth: 1] + ], + splits: [ + # base0 + text: [fill: "#839496", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + # base01, base00 + rect: [fill: "#586e75", stroke: "#657b83", strokeWidth: 1], + # base00 + children: [fill: "#657b83", stroke: "#657b83", strokeWidth: 1] + ], + yes: [ + # green + text: [fill: "#859900"], + # base00 + path: [stroke: "#657b83", strokeWidth: 1] + ], + no: [ + # red + text: [fill: "#dc322f"], + # base00 + path: [stroke: "#657b83", strokeWidth: 1] + ] + ] + end - The default Vega specification is designed to be a good starting point for visualizing a model, but it is - possible to customize the specification by passing in a map of Vega properties to the `to_vega/2` function. - Refer to `Custom Vega Specifications` for more details on how to do this. + @doc """ + A light and playful theme + """ + style :playful_light do + [ + background: "#f0f0f0", + padding: 10, + leaves: [ + text: [fill: "#000", font_size: 12, font_style: "italic", font_weight: "bold"], + rect: [fill: "#e91e63", stroke: "#000", stroke_width: 1, radius: 5] + ], + splits: [ + text: [fill: "#000", font_size: 12, font_style: "normal", font_weight: "bold"], + children: [ + fill: "#000", + font_size: 12, + font_style: "normal", + font_weight: "bold" + ], + rect: [fill: "#8bc34a", stroke: "#000", stroke_width: 1, radius: 10] + ], + yes: [ + path: [stroke: "#4caf50", stroke_width: 2] + ], + no: [ + path: [stroke: "#f44336", stroke_width: 2] + ] + ] + end - By default, the Vega specification includes the following entities to use for rendering the model: - * `:width` - The width of the plot in pixels - * `:height` - The height of the plot in pixels - * `:padding` - The padding in pixels to add around the visualization. If a number, specifies padding for all sides. If an object, the value should have the format `[left: value, right: value, top: value, bottom: value]` - * `:leafs` - Specifies characteristics of leaf nodes - * `:inner_nodes` - Specifies characteristics of inner nodes - * `:links` - Specifies characteristics of links between nodes + @doc """ + A dark and playful theme + """ + style :playful_dark do + [ + background: "#333", + padding: 10, + leaves: [ + text: [fill: "#fff", font_size: 12, font_style: "italic", font_weight: "bold"], + rect: [fill: "#e91e63", stroke: "#fff", stroke_width: 1, radius: 5] + ], + splits: [ + text: [fill: "#fff", font_size: 12, font_style: "normal", font_weight: "bold"], + rect: [fill: "#8bc34a", stroke: "#fff", stroke_width: 1, radius: 10] + ], + yes: [ + text: [fill: "#4caf50"], + path: [stroke: "#4caf50", stroke_width: 2] + ], + no: [ + text: [fill: "#f44336"], + path: [stroke: "#f44336", stroke_width: 2] + ] + ] + end - ## Custom Vega Specifications + @doc """ + A dark theme + """ + style :dark do + [ + background: "#333", + padding: 10, + leaves: [ + text: [fill: "#fff", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + rect: [fill: "#666", stroke: "#fff", strokeWidth: 1] + ], + splits: [ + text: [fill: "#fff", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + rect: [fill: "#444", stroke: "#fff", strokeWidth: 1], + children: [fill: "#fff", stroke: "#fff", strokeWidth: 1] + ] + ] + end - The default Vega specification is designed to be a good starting point for visualizing a model, but it is - possible to customize the specification by passing in a map of Vega properties to the `to_vega/2` function. - You can find the full list of Vega properties [here](https://vega.github.io/vega/docs/specification/). + @doc """ + A high contrast theme + """ + style :high_contrast do + [ + background: "#000", + padding: 10, + leaves: [ + text: [fill: "#fff", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + rect: [fill: "#333", stroke: "#fff", strokeWidth: 1] + ], + splits: [ + text: [fill: "#fff", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + rect: [fill: "#666", stroke: "#fff", strokeWidth: 1] + ] + ] + end - It is suggested that you use the data attributes provided by the default specification as a starting point, since they - provide the necessary data transformation to convert the model into a tree structure that can be visualized by Vega. - If you would like to customize the default specification, you can use `EXGBoost.Plotting.to_vega/1` to get the default - specification, and then modify it as needed. + @doc """ + A light theme + """ + style :light do + [ + background: "#f0f0f0", + padding: 10, + leaves: [ + text: [fill: "#000", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + rect: [fill: "#ddd", stroke: "#000", strokeWidth: 1] + ], + splits: [ + text: [fill: "#000", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + rect: [fill: "#bbb", stroke: "#000", strokeWidth: 1] + ] + ] + end - Once you have a custom specification, you can pass it to `VegaLite.from_json/1` to create a new `VegaLite` struct, after which - you can use the functions provided by the `VegaLite` module to render the model. + @doc """ + A theme based on the [Monokai](https://monokai.pro/) color palette + """ + style :monokai do + [ + background: "#272822", + leaves: [ + text: [fill: "#f8f8f2", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + rect: [fill: "#3e3d32", stroke: "#66d9ef", strokeWidth: 1] + ], + splits: [ + text: [fill: "#f8f8f2", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + rect: [fill: "#66d9ef", stroke: "#f8f8f2", strokeWidth: 1], + children: [fill: "#f8f8f2", stroke: "#f8f8f2", strokeWidth: 1] + ], + yes: [ + text: [fill: "#a6e22e"], + path: [stroke: "#f8f8f2", strokeWidth: 1] + ], + no: [ + text: [fill: "#f92672"], + path: [stroke: "#f8f8f2", strokeWidth: 1] + ] + ] + end - ## Specification Validation - You can optionally validate your specification against the Vega schema by passing the `validate: true` option to `to_vega/2`. - This will raise an error if the specification is invalid. This is useful if you are creating a custom specification and want - to ensure that it is valid. Note that this will only validate the specification against the Vega schema, and not against the - VegaLite schema. This requires the [`ex_json_schema`] package to be installed. + @doc """ + A theme based on the [Dracula](https://draculatheme.com/) color palette + """ + style :dracula do + [ + background: "#282a36", + leaves: [ + text: [fill: "#f8f8f2", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + rect: [fill: "#44475a", stroke: "#ff79c6", strokeWidth: 1] + ], + splits: [ + text: [fill: "#f8f8f2", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + rect: [fill: "#ff79c6", stroke: "#f8f8f2", strokeWidth: 1], + children: [fill: "#f8f8f2", stroke: "#f8f8f2", strokeWidth: 1] + ], + yes: [ + text: [fill: "#50fa7b"], + path: [stroke: "#f8f8f2", strokeWidth: 1] + ], + no: [ + text: [fill: "#ff5555"], + path: [stroke: "#f8f8f2", strokeWidth: 1] + ] + ] + end - ## Livebook Integration + @doc """ + A theme based on the [Nord](https://www.nordtheme.com/) color palette + """ + style :nord do + [ + background: "#2e3440", + leaves: [ + text: [fill: "#d8dee9", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + rect: [fill: "#3b4252", stroke: "#88c0d0", strokeWidth: 1] + ], + splits: [ + text: [fill: "#d8dee9", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + rect: [fill: "#88c0d0", stroke: "#d8dee9", strokeWidth: 1], + children: [fill: "#d8dee9", stroke: "#d8dee9", strokeWidth: 1] + ], + yes: [ + text: [fill: "#a3be8c"], + path: [stroke: "#d8dee9", strokeWidth: 1] + ], + no: [ + text: [fill: "#bf616a"], + path: [stroke: "#d8dee9", strokeWidth: 1] + ] + ] + end - This module also provides a `Kino.Render` implementation for `EXGBoost.Booster` which allows - models to be rendered directly in Livebook. This is done by converting the model into a Vega specification - and then using the `Kino.Render` implementation for Elixir's [`VegaLite`](https://hexdocs.pm/vega_lite/VegaLite.html) API - to render the model. + @doc """ + A theme based on the [Material](https://material.io/design/color/the-color-system.html#tools-for-picking-colors) color palette + """ + style :material do + [ + background: "#263238", + leaves: [ + text: [fill: "#eceff1", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + rect: [fill: "#37474f", stroke: "#80cbc4", strokeWidth: 1] + ], + splits: [ + text: [fill: "#eceff1", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + rect: [fill: "#80cbc4", stroke: "#eceff1", strokeWidth: 1], + children: [fill: "#eceff1", stroke: "#eceff1", strokeWidth: 1] + ], + yes: [ + text: [fill: "#c5e1a5"], + path: [stroke: "#eceff1", strokeWidth: 1] + ], + no: [ + text: [fill: "#ef9a9a"], + path: [stroke: "#eceff1", strokeWidth: 1] + ] + ] + end + @doc """ + A theme based on the One Dark color palette + """ + style :one_dark do + [ + background: "#282c34", + leaves: [ + text: [fill: "#abb2bf", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + rect: [fill: "#3b4048", stroke: "#98c379", strokeWidth: 1] + ], + splits: [ + text: [fill: "#abb2bf", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + rect: [fill: "#98c379", stroke: "#abb2bf", strokeWidth: 1], + children: [fill: "#abb2bf", stroke: "#abb2bf", strokeWidth: 1] + ], + yes: [ + text: [fill: "#98c379"], + path: [stroke: "#abb2bf", strokeWidth: 1] + ], + no: [ + text: [fill: "#e06c75"], + path: [stroke: "#abb2bf", strokeWidth: 1] + ] + ] + end - . The Vega specification is then passed to [VegaLite](https://hexdocs.pm/vega_lite/readme.html) + @doc """ + A theme based on the [Gruvbox](https://github.com/morhetz/gruvbox) color palette + """ + style :gruvbox do + [ + background: "#282828", + leaves: [ + text: [fill: "#ebdbb2", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + rect: [fill: "#3c3836", stroke: "#b8bb26", strokeWidth: 1] + ], + splits: [ + text: [fill: "#ebdbb2", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + rect: [fill: "#b8bb26", stroke: "#ebdbb2", strokeWidth: 1], + children: [fill: "#ebdbb2", stroke: "#ebdbb2", strokeWidth: 1] + ], + yes: [ + text: [fill: "#b8bb26"], + path: [stroke: "#ebdbb2", strokeWidth: 1] + ], + no: [ + text: [fill: "#fb4934"], + path: [stroke: "#ebdbb2", strokeWidth: 1] + ] + ] + end + @doc """ + A dark theme based on the [Horizon](https://www.horizon.io/) color palette + """ + style :horizon_dark do + [ + background: "#1C1E26", + leaves: [ + text: [fill: "#E3E6EE", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + rect: [fill: "#232530", stroke: "#F43E5C", strokeWidth: 1] + ], + splits: [ + text: [fill: "#E3E6EE", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + rect: [fill: "#F43E5C", stroke: "#E3E6EE", strokeWidth: 1], + children: [fill: "#E3E6EE", stroke: "#E3E6EE", strokeWidth: 1] + ], + yes: [ + text: [fill: "#48B685"], + path: [stroke: "#E3E6EE", strokeWidth: 1] + ], + no: [ + text: [fill: "#F43E5C"], + path: [stroke: "#E3E6EE", strokeWidth: 1] + ] + ] + end + @doc """ + A light theme based on the [Horizon](https://www.horizon.io/) color palette """ + style :horizon_light do + [ + background: "#FDF0ED", + leaves: [ + text: [fill: "#1A2026", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], + rect: [fill: "#F7E3D3", stroke: "#F43E5C", strokeWidth: 1] + ], + splits: [ + text: [fill: "#1A2026", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], + rect: [fill: "#F43E5C", stroke: "#1A2026", strokeWidth: 1], + children: [fill: "#1A2026", stroke: "#1A2026", strokeWidth: 1] + ], + yes: [ + text: [fill: "#48B685"], + path: [stroke: "#1A2026", strokeWidth: 1] + ], + no: [ + text: [fill: "#F43E5C"], + path: [stroke: "#1A2026", strokeWidth: 1] + ] + ] + end + HTTPoison.start() @schema HTTPoison.get!("https://vega.github.io/schema/vega/v5.json").body @@ -136,27 +473,10 @@ defmodule EXGBoost.Plotting do @plotting_params [ style: [ - doc: "The style to use for the visualization.", + doc: + "The style to use for the visualization. Refer to `EXGBoost.Plotting.Styles` for a list of available styles.", default: :solarized_light, - type: - {:in, - [ - :solarized_light, - :solarized_dark, - :playful_light, - :playful_dark, - :dark, - :light, - :nord, - :dracula, - :gruvbox, - :high_contrast, - :monokai, - :material, - :one_dark, - nil, - false - ]} + type: {:in, Keyword.keys(@styles)} ], rankdir: [ doc: "Determines the direction of the graph.", @@ -343,13 +663,89 @@ defmodule EXGBoost.Plotting do ] @plotting_schema NimbleOptions.new!(@plotting_params) - @defaults NimbleOptions.validate!([], @plotting_schema) + @moduledoc """ + Functions for plotting EXGBoost `Booster` models using [Vega](https://vega.github.io/vega/) + + Fundamentally, all this module does is convert a `Booster` into a format that can be + ingested by Vega, and apply some default configuations that only account for a subset of the configurations + that can be set by a Vega spec directly. The functions provided in this module are designed to have opinionated + defaults that can be used to quickly visualize a model, but the full power of Vega is available by using the + `to_tabular/1` function to convert the model into a tabular format, and then using the `to_vega/2` function + to convert the tabular format into a Vega specification. + + ## Default Vega Specification + + The default Vega specification is designed to be a good starting point for visualizing a model, but it is + possible to customize the specification by passing in a map of Vega properties to the `to_vega/2` function. + Refer to `Custom Vega Specifications` for more details on how to do this. + + By default, the Vega specification includes the following entities to use for rendering the model: + * `:width` - The width of the plot in pixels + * `:height` - The height of the plot in pixels + * `:padding` - The padding in pixels to add around the visualization. If a number, specifies padding for all sides. If an object, the value should have the format `[left: value, right: value, top: value, bottom: value]` + * `:leafs` - Specifies characteristics of leaf nodes + * `:inner_nodes` - Specifies characteristics of inner nodes + * `:links` - Specifies characteristics of links between nodes + + ## Custom Vega Specifications + + The default Vega specification is designed to be a good starting point for visualizing a model, but it is + possible to customize the specification by passing in a map of Vega properties to the `to_vega/2` function. + You can find the full list of Vega properties [here](https://vega.github.io/vega/docs/specification/). + + It is suggested that you use the data attributes provided by the default specification as a starting point, since they + provide the necessary data transformation to convert the model into a tree structure that can be visualized by Vega. + If you would like to customize the default specification, you can use `EXGBoost.Plotting.to_vega/1` to get the default + specification, and then modify it as needed. + + Once you have a custom specification, you can pass it to `VegaLite.from_json/1` to create a new `VegaLite` struct, after which + you can use the functions provided by the `VegaLite` module to render the model. + + ## Specification Validation + You can optionally validate your specification against the Vega schema by passing the `validate: true` option to `to_vega/2`. + This will raise an error if the specification is invalid. This is useful if you are creating a custom specification and want + to ensure that it is valid. Note that this will only validate the specification against the Vega schema, and not against the + VegaLite schema. This requires the [`ex_json_schema`] package to be installed. + + ## Livebook Integration + + This module also provides a `Kino.Render` implementation for `EXGBoost.Booster` which allows + models to be rendered directly in Livebook. This is done by converting the model into a Vega specification + and then using the `Kino.Render` implementation for Elixir's [`VegaLite`](https://hexdocs.pm/vega_lite/VegaLite.html) API + to render the model. + + . The Vega specification is then passed to [VegaLite](https://hexdocs.pm/vega_lite/readme.html) + + ## Plotting Parameters + + This module exposes a high-level API for customizing the EXGBoost model visualization, but it is also possible to + customize the Vega specification directly. You can also choose to pass in Vega Mark specifications to customize the + appearance of the nodes and links in the visualization outside of the parameteres specified below. Refer to the + [Vega documentation](https://vega.github.io/vega/docs/marks/) for more details on how to do this. + + #{NimbleOptions.docs(@plotting_params)} + + + ## Styles + + Styles are a keyword-map that adhere to the plotting schema as defined in `EXGBoost.Plotting`. + `EXGBoost.Plotting.Styles` provides a set of predefined styles that can be used to quickly customize the appearance of the visualization. + + + Refer to the `EXGBoost.Plotting.Styles` module for a list of available styles. You can pass a style to the `:style` + option as an atom or string, and it will be applied to the visualization. Styles will override any other options that are passed + for each option where the style defined a value. For example, if you pass `:solarized_light` as the style, and also pass + `:background` as an option, the `:background` option will be ignored since the `:solarized_light` style defines its own value for `:background`. + """ + def get_schema(), do: @schema def get_defaults(), do: @defaults + def get_styles(), do: @styles + defp validate_spec(spec) do case ExJsonSchema.Validator.validate(get_schema(), spec) do :ok -> @@ -385,7 +781,7 @@ defmodule EXGBoost.Plotting do end end - def deep_merge_kw(a, b) do + defp deep_merge_kw(a, b) do Keyword.merge(a, b, fn _key, val_a, val_b when is_list(val_a) and is_list(val_b) -> deep_merge_kw(val_a, val_b) @@ -463,7 +859,7 @@ defmodule EXGBoost.Plotting do opts = unless opts[:style] in [nil, false] do - style = apply(EXGBoost.Plotting.Styles, opts[:style], []) + style = apply(__MODULE__, opts[:style], []) deep_merge_kw(opts, style) else @@ -789,7 +1185,7 @@ defmodule EXGBoost.Plotting do opts = unless opts[:style] in [nil, false] do - style = apply(EXGBoost.Plotting.Styles, opts[:style], []) + style = apply(__MODULE__, opts[:style], []) deep_merge_kw(opts, style) else @@ -1209,7 +1605,6 @@ defmodule EXGBoost.Plotting do }) spec = Map.merge(spec, tlk) |> Map.delete("style") - File.write!("/Users/andres/Documents/exgboost/spec.json", Jason.encode!(spec)) spec = if opts[:validate], do: validate_spec(spec), else: spec Jason.encode!(spec) |> VegaLite.from_json() @@ -1270,6 +1665,10 @@ defmodule EXGBoost.Plotting do defp capitalize(<>) when first in ?a..?z, do: <> defp capitalize(rest), do: rest + + def __after_compile__(env) do + IO.inspect(env) + end end defimpl Kino.Render, for: EXGBoost.Booster do diff --git a/lib/exgboost/plotting/style.ex b/lib/exgboost/plotting/style.ex new file mode 100644 index 0000000..002a62b --- /dev/null +++ b/lib/exgboost/plotting/style.ex @@ -0,0 +1,16 @@ +defmodule EXGBoost.Plotting.Style do + @moduledoc false + defmacro __using__(_opts) do + quote do + import EXGBoost.Plotting.Style + Module.register_attribute(__MODULE__, :styles, accumulate: true) + end + end + + defmacro style(style_name, do: body) do + quote do + def unquote(style_name)(), do: unquote(body) + Module.put_attribute(__MODULE__, :styles, {unquote(style_name), unquote(body)}) + end + end +end diff --git a/lib/exgboost/plotting/styles.ex b/lib/exgboost/plotting/styles.ex index 62d4807..cd6fdf8 100644 --- a/lib/exgboost/plotting/styles.ex +++ b/lib/exgboost/plotting/styles.ex @@ -1,293 +1,18 @@ defmodule EXGBoost.Plotting.Styles do + @bst File.cwd!() |> Path.join("test/data/model.json") |> EXGBoost.read_model() + @moduledoc """ - A style is a keyword-map that adheres to the plotting schema - as defined in `EXGBoost.Plotting`. +
+ #{Enum.map(EXGBoost.Plotting.get_styles(), fn {name, _style} -> """ +
+

#{name}

+
+        
+        #{EXGBoost.Plotting.to_vega(@bst, style: name, height: 200, width: 300).spec |> Jason.encode!()}
+        
+      
+
+ """ end) |> Enum.join("\n\n")} +
""" - - def solarized_light(), - do: [ - # base3 - background: "#fdf6e3", - leaves: [ - # base01 - text: [fill: "#586e75", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], - # base2, base1 - rect: [fill: "#eee8d5", stroke: "#93a1a1", strokeWidth: 1] - ], - splits: [ - # base01 - text: [fill: "#586e75", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], - # base1, base00 - rect: [fill: "#93a1a1", stroke: "#657b83", strokeWidth: 1], - # base00 - children: [fill: "#657b83", stroke: "#657b83", strokeWidth: 1] - ], - yes: [ - # green - text: [fill: "#859900"], - # base00 - path: [stroke: "#657b83", strokeWidth: 1] - ], - no: [ - # red - text: [fill: "#dc322f"], - # base00 - path: [stroke: "#657b83", strokeWidth: 1] - ] - ] - - def solarized_dark(), - do: [ - # base03 - background: "#002b36", - leaves: [ - # base0 - text: [fill: "#839496", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], - # base02, base01 - rect: [fill: "#073642", stroke: "#586e75", strokeWidth: 1] - ], - splits: [ - # base0 - text: [fill: "#839496", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], - # base01, base00 - rect: [fill: "#586e75", stroke: "#657b83", strokeWidth: 1], - # base00 - children: [fill: "#657b83", stroke: "#657b83", strokeWidth: 1] - ], - yes: [ - # green - text: [fill: "#859900"], - # base00 - path: [stroke: "#657b83", strokeWidth: 1] - ], - no: [ - # red - text: [fill: "#dc322f"], - # base00 - path: [stroke: "#657b83", strokeWidth: 1] - ] - ] - - def playful_light(), - do: [ - background: "#f0f0f0", - padding: 10, - leaves: [ - text: [fill: "#000", font_size: 12, font_style: "italic", font_weight: "bold"], - rect: [fill: "#e91e63", stroke: "#000", stroke_width: 1, radius: 5] - ], - splits: [ - text: [fill: "#000", font_size: 12, font_style: "normal", font_weight: "bold"], - children: [ - fill: "#000", - font_size: 12, - font_style: "normal", - font_weight: "bold" - ], - rect: [fill: "#8bc34a", stroke: "#000", stroke_width: 1, radius: 10] - ], - yes: [ - path: [stroke: "#4caf50", stroke_width: 2] - ], - no: [ - path: [stroke: "#f44336", stroke_width: 2] - ] - ] - - def playful_dark(), - do: [ - background: "#333", - padding: 10, - leaves: [ - text: [fill: "#fff", font_size: 12, font_style: "italic", font_weight: "bold"], - rect: [fill: "#e91e63", stroke: "#fff", stroke_width: 1, radius: 5] - ], - splits: [ - text: [fill: "#fff", font_size: 12, font_style: "normal", font_weight: "bold"], - rect: [fill: "#8bc34a", stroke: "#fff", stroke_width: 1, radius: 10] - ], - yes: [ - text: [fill: "#4caf50"], - path: [stroke: "#4caf50", stroke_width: 2] - ], - no: [ - text: [fill: "#f44336"], - path: [stroke: "#f44336", stroke_width: 2] - ] - ] - - def dark(), - do: [ - background: "#333", - padding: 10, - leaves: [ - text: [fill: "#fff", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], - rect: [fill: "#666", stroke: "#fff", strokeWidth: 1] - ], - splits: [ - text: [fill: "#fff", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], - rect: [fill: "#444", stroke: "#fff", strokeWidth: 1], - children: [fill: "#fff", stroke: "#fff", strokeWidth: 1] - ] - ] - - def high_contrast(), - do: [ - background: "#000", - padding: 10, - leaves: [ - text: [fill: "#fff", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], - rect: [fill: "#333", stroke: "#fff", strokeWidth: 1] - ], - splits: [ - text: [fill: "#fff", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], - rect: [fill: "#666", stroke: "#fff", strokeWidth: 1] - ] - ] - - def light(), - do: [ - background: "#f0f0f0", - padding: 10, - leaves: [ - text: [fill: "#000", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], - rect: [fill: "#ddd", stroke: "#000", strokeWidth: 1] - ], - splits: [ - text: [fill: "#000", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], - rect: [fill: "#bbb", stroke: "#000", strokeWidth: 1] - ] - ] - - def monokai(), - do: [ - background: "#272822", - leaves: [ - text: [fill: "#f8f8f2", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], - rect: [fill: "#3e3d32", stroke: "#66d9ef", strokeWidth: 1] - ], - splits: [ - text: [fill: "#f8f8f2", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], - rect: [fill: "#66d9ef", stroke: "#f8f8f2", strokeWidth: 1], - children: [fill: "#f8f8f2", stroke: "#f8f8f2", strokeWidth: 1] - ], - yes: [ - text: [fill: "#a6e22e"], - path: [stroke: "#f8f8f2", strokeWidth: 1] - ], - no: [ - text: [fill: "#f92672"], - path: [stroke: "#f8f8f2", strokeWidth: 1] - ] - ] - - def dracula(), - do: [ - background: "#282a36", - leaves: [ - text: [fill: "#f8f8f2", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], - rect: [fill: "#44475a", stroke: "#ff79c6", strokeWidth: 1] - ], - splits: [ - text: [fill: "#f8f8f2", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], - rect: [fill: "#ff79c6", stroke: "#f8f8f2", strokeWidth: 1], - children: [fill: "#f8f8f2", stroke: "#f8f8f2", strokeWidth: 1] - ], - yes: [ - text: [fill: "#50fa7b"], - path: [stroke: "#f8f8f2", strokeWidth: 1] - ], - no: [ - text: [fill: "#ff5555"], - path: [stroke: "#f8f8f2", strokeWidth: 1] - ] - ] - - def nord(), - do: [ - background: "#2e3440", - leaves: [ - text: [fill: "#d8dee9", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], - rect: [fill: "#3b4252", stroke: "#88c0d0", strokeWidth: 1] - ], - splits: [ - text: [fill: "#d8dee9", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], - rect: [fill: "#88c0d0", stroke: "#d8dee9", strokeWidth: 1], - children: [fill: "#d8dee9", stroke: "#d8dee9", strokeWidth: 1] - ], - yes: [ - text: [fill: "#a3be8c"], - path: [stroke: "#d8dee9", strokeWidth: 1] - ], - no: [ - text: [fill: "#bf616a"], - path: [stroke: "#d8dee9", strokeWidth: 1] - ] - ] - - def material(), - do: [ - background: "#263238", - leaves: [ - text: [fill: "#eceff1", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], - rect: [fill: "#37474f", stroke: "#80cbc4", strokeWidth: 1] - ], - splits: [ - text: [fill: "#eceff1", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], - rect: [fill: "#80cbc4", stroke: "#eceff1", strokeWidth: 1], - children: [fill: "#eceff1", stroke: "#eceff1", strokeWidth: 1] - ], - yes: [ - text: [fill: "#c5e1a5"], - path: [stroke: "#eceff1", strokeWidth: 1] - ], - no: [ - text: [fill: "#ef9a9a"], - path: [stroke: "#eceff1", strokeWidth: 1] - ] - ] - - def one_dark(), - do: [ - background: "#282c34", - leaves: [ - text: [fill: "#abb2bf", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], - rect: [fill: "#3b4048", stroke: "#98c379", strokeWidth: 1] - ], - splits: [ - text: [fill: "#abb2bf", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], - rect: [fill: "#98c379", stroke: "#abb2bf", strokeWidth: 1], - children: [fill: "#abb2bf", stroke: "#abb2bf", strokeWidth: 1] - ], - yes: [ - text: [fill: "#98c379"], - path: [stroke: "#abb2bf", strokeWidth: 1] - ], - no: [ - text: [fill: "#e06c75"], - path: [stroke: "#abb2bf", strokeWidth: 1] - ] - ] - - def gruvbox(), - do: [ - background: "#282828", - leaves: [ - text: [fill: "#ebdbb2", fontSize: 12, fontStyle: "normal", fontWeight: "normal"], - rect: [fill: "#3c3836", stroke: "#b8bb26", strokeWidth: 1] - ], - splits: [ - text: [fill: "#ebdbb2", fontSize: 12, fontStyle: "normal", fontWeight: "bold"], - rect: [fill: "#b8bb26", stroke: "#ebdbb2", strokeWidth: 1], - children: [fill: "#ebdbb2", stroke: "#ebdbb2", strokeWidth: 1] - ], - yes: [ - text: [fill: "#b8bb26"], - path: [stroke: "#ebdbb2", strokeWidth: 1] - ], - no: [ - text: [fill: "#fb4934"], - path: [stroke: "#ebdbb2", strokeWidth: 1] - ] - ] end diff --git a/mix.exs b/mix.exs index 568dc1f..eb55c5b 100644 --- a/mix.exs +++ b/mix.exs @@ -126,6 +126,38 @@ defmodule EXGBoost.MixProject do } }); + + + + + + + """ end diff --git a/test/data/model.json b/test/data/model.json new file mode 100644 index 0000000..6f3a378 Binary files /dev/null and b/test/data/model.json differ