<commit_before>#+SETUPFILE: setup.org

* Contents                                                         :toc_3_gh:
 - [[#namespace-thingcolorgradients][Namespace: thi.ng.color.gradients]]
     - [[#cosine-based-gradient-generation][Cosine based gradient generation]]
         - [[#presets][Presets]]
         - [[#implementation][Implementation]]
         - [[#example-usage][Example usage]]
         - [[#gradient-presets-visualization][Gradient presets visualization]]
     - [[#complete-namespace-definition][Complete namespace definition]]

* Namespace: thi.ng.color.gradients

** Cosine based gradient generation

Based on method by iq (<NAME>): http://v.gd/B2aySt

*** Presets

Here we define a number of RGB gradient presets, primarily useful for
data visualization purposes:

#+BEGIN_SRC clojure :noweb-ref generators
  (def cosine-schemes
    {:rainbow1 [[0.5 0.5 0.5] [0.5 0.5 0.5] [1.0 1.0 1.0] [0 0.3333 0.6666]]
     :rainbow2 [[0.5 0.5 0.5] [0.666 0.666 0.666] [1.0 1.0 1.0] [0 0.3333 0.6666]]
     :rainbow3 [[0.5 0.5 0.5] [0.75 0.75 0.75] [1.0 1.0 1.0] [0 0.3333 0.6666]]
     :rainbow4 [[0.5 0.5 0.5] [1 1 1] [1.0 1.0 1.0] [0 0.3333 0.6666]]
     :yellow-magenta-cyan [[1 0.5 0.5] [0.5 0.5 0.5] [0.75 1.0 0.6666] [0.8 1.0 0.4]]
     :orange-blue [[0.5 0.5 0.5] [0.5 0.5 0.5] [0.8 0.8 0.5] [0 0.2 0.5]]
     :green-magenta [[0.6666 0.5 0.5] [0.5 0.6666 0.5] [0.6666 0.666 0.5] [0.25 0.0 0.5]]
     :green-red [[0.5 0.5 0] [0.5 0.5 0] [0.5 0.5 0] [0.5 0.0 0]]
     :green-cyan [[0.0 0.5 0.5] [0 0.5 0.5] [0.0 0.3333 0.5] [0.0 0.6666 0.5]]
     :yellow-red [[0.5 0.5 0] [0.5 0.5 0] [0.1 0.5 0] [0.0 0.0 0]]
     :blue-cyan [[0.0 0.5 0.5] [0 0.5 0.5] [0.0 0.45 0.3333] [0.0 0.5 0.6666]]
     :red-blue [[0.5 0 0.5] [0.5 0 0.5] [0.5 0 0.5] [0 0 0.5]]})
#+END_SRC

Diagrams of the presets showing their channel curves and resulting
gradients (using 100 samples):

| [[http://media.thi.ng/color/presets/rainbow1.svg]]            | [[http://media.thi.ng/color/presets/rainbow2.svg]]    |
| :rainbow1                                                 | :rainbow2                                         |
| [[http://media.thi.ng/color/presets/rainbow3.svg]]            | [[http://media.thi.ng/color/presets/rainbow4.svg]]    |
| :rainbow3                                                 | :rainbow4                                         |
| [[http://media.thi.ng/color/presets/yellow-magenta-cyan.svg]] | [[http://media.thi.ng/color/presets/orange-blue.svg]] |
| :yellow-magenta-cyan preset                               | :orange-blue                                      |
| [[http://media.thi.ng/color/presets/green-magenta.svg]]       | [[http://media.thi.ng/color/presets/green-red.svg]]   |
| :green-magenta                                            | :green-red                                        |
| [[http://media.thi.ng/color/presets/green-cyan.svg]]          | [[http://media.thi.ng/color/presets/blue-cyan.svg]]   |
| :green-cyan                                               | :blue-cyan                                        |
| [[http://media.thi.ng/color/presets/yellow-red.svg]]          | [[http://media.thi.ng/color/presets/red-blue.svg]]    |
| :yellow-red                                               | :red-blue                                         |

*** Implementation

The two functions below implement the gradient generation function:
=cosine-gradient-color= to compute single colors and
=cosine-gradient-scheme= to create a vector of n tuples covering the
full gradient range.

*Note:* These function are not restricted to RGB colors and can be
used in many other contexts - think of it as an ND waveform
generator...

#+BEGIN_SRC clojure :noweb-ref generators
  (defn cosine-gradient-color
    [offset amp fmod phase t]
    (col/rgba
     (mapv
      (fn [a b c d] (m/clamp (+ a (* b (Math/cos (* TWO_PI (+ (* c t) d))))) 0 1))
      offset amp fmod phase)))

  (defn cosine-gradient
    "Takes a length n and 4 cosine coefficients (for colors usually 3 or
    4-element vectors) and produces vector of n new RGBA colors, with
    each of its elements defined by an AM & FM cosine wave and clamped
    to the [0 1] interval."
    [n offset amp fmod phase]
    (mapv #(cosine-gradient-color offset amp fmod phase %) (m/norm-range (dec n))))
#+END_SRC

*** Example usage

#+BEGIN_SRC clojure
  ;; using a preset
  (def my-grad
    (->> :red-blue
         (grad/cosine-schemes)
         (apply grad/cosine-gradient 100)))

  ;; specifying cosine coefficients directly
  (def my-grad
    (grad/cosine-gradient 100 [0.5 0 0.5] [0.5 0 0.5] [0.5 0 0.5] [0 0 0.5]))
#+END_SRC

*** Gradient presets visualization

This following snippet is *not* part of the library and only used to
create the above preset visualizations. Requires http://thi.ng/geom to
be added to your REPL/project in order to run...

When tangling this file, the code below will be saved in the
=/babel/dev/= subdir of this project...

#+BEGIN_SRC clojure :tangle ../babel/dev/cosine-previews.clj :mkdirp yes :padline no
  (require '[thi.ng.color.core :as col])
  (require '[thi.ng.color.gradients :as grad])
  (require '[thi.ng.geom.viz.core :as viz])
  (require '[thi.ng.geom.svg.core :as svg])
  (require '[thi.ng.math.core :as m])

  (defn channel-specs
    [colors]
    (map-indexed
     (fn [idx col]
       {:values  (viz/uniform-domain-points [0 1] (map #(nth (deref %) idx) colors))
        :attribs {:fill "none" :stroke col}
        :layout  viz/svg-line-plot})
     ["red" "green" "blue"]))

  (defn color-bars
    [x1 x2 y w h colors]
    (let [n (dec (count colors))]
      (for [i (m/norm-range n)]
        (svg/rect [(m/mix x1 x2 i) y] w h {:fill (colors (int (* i n)))}))))

  (doseq [[id coeffs] grad/cosine-schemes]
    (let [colors (apply grad/cosine-gradient 100 coeffs)]
      (->> {:x-axis (viz/linear-axis
                     {:domain [0 1] :range [50 580] :major 0.5 :minor 0.125 :pos 250})
            :y-axis (viz/linear-axis
                     {:domain [0 1] :range [250 20] :major 0.2 :minor 0.1 :pos 50
                      :label-dist 15 :label {:text-anchor "end"}})
            :grid   {:minor-y true}
            :data   (channel-specs colors)}
           (viz/svg-plot2d-cartesian)
           (svg/svg
            {:width 600 :height 300}
            (color-bars 50 570 280 10 20 colors))
           (svg/serialize)
           (spit (str (name id) ".svg")))))
#+END_SRC

** Complete namespace definition

#+BEGIN_SRC clojure :tangle ../babel/src/thi/ng/color/gradients.cljc :noweb yes :mkdirp yes :padline no
  (ns thi.ng.color.gradients
    #?(:cljs
    (:require-macros
     [thi.ng.math.macros :as mm]))
    (:require
     [thi.ng.math.core :as m :refer [PI TWO_PI]]
     [thi.ng.color.core :as col]
     #?(:clj [thi.ng.math.macros :as mm])))

  <<generators>>
#+END_SRC<commit_msg>minor refinement of gradient presets, add extra arity cosine-gradient<commit_after>#+SETUPFILE: setup.org

* Contents                                                         :toc_3_gh:
 - [[#namespace-thingcolorgradients][Namespace: thi.ng.color.gradients]]
     - [[#cosine-based-gradient-generation][Cosine based gradient generation]]
         - [[#presets][Presets]]
         - [[#implementation][Implementation]]
         - [[#example-usage][Example usage]]
         - [[#gradient-presets-visualization][Gradient presets visualization]]
     - [[#complete-namespace-definition][Complete namespace definition]]

* Namespace: thi.ng.color.gradients

** Cosine based gradient generation

Based on method by iq (<NAME>): http://v.gd/B2aySt

*** Presets

Here we define a number of RGB gradient presets, primarily useful for
data visualization purposes:

#+BEGIN_SRC clojure :noweb-ref generators
  (def cosine-schemes
    {:rainbow1 [[0.5 0.5 0.5] [0.5 0.5 0.5] [1.0 1.0 1.0] [0 0.3333 0.6666]]
     :rainbow2 [[0.5 0.5 0.5] [0.666 0.666 0.666] [1.0 1.0 1.0] [0 0.3333 0.6666]]
     :rainbow3 [[0.5 0.5 0.5] [0.75 0.75 0.75] [1.0 1.0 1.0] [0 0.3333 0.6666]]
     :rainbow4 [[0.5 0.5 0.5] [1 1 1] [1.0 1.0 1.0] [0 0.3333 0.6666]]
     :yellow-magenta-cyan [[1 0.5 0.5] [0.5 0.5 0.5] [0.75 1.0 0.6666] [0.8 1.0 0.3333]]
     :orange-blue [[0.5 0.5 0.5] [0.5 0.5 0.5] [0.8 0.8 0.5] [0 0.2 0.5]]
     :green-magenta [[0.6666 0.5 0.5] [0.5 0.6666 0.5] [0.6666 0.666 0.5] [0.2 0.0 0.5]]
     :green-red [[0.5 0.5 0] [0.5 0.5 0] [0.5 0.5 0] [0.5 0.0 0]]
     :green-cyan [[0.0 0.5 0.5] [0 0.5 0.5] [0.0 0.3333 0.5] [0.0 0.6666 0.5]]
     :yellow-red [[0.5 0.5 0] [0.5 0.5 0] [0.1 0.5 0] [0.0 0.0 0]]
     :blue-cyan [[0.0 0.5 0.5] [0 0.5 0.5] [0.0 0.5 0.3333] [0.0 0.5 0.6666]]
     :red-blue [[0.5 0 0.5] [0.5 0 0.5] [0.5 0 0.5] [0 0 0.5]]})
#+END_SRC

Diagrams of the presets showing their channel curves and resulting
gradients (using 100 samples):

| [[http://media.thi.ng/color/presets/rainbow1.svg]]            | [[http://media.thi.ng/color/presets/rainbow2.svg]]    |
| :rainbow1                                                 | :rainbow2                                         |
| [[http://media.thi.ng/color/presets/rainbow3.svg]]            | [[http://media.thi.ng/color/presets/rainbow4.svg]]    |
| :rainbow3                                                 | :rainbow4                                         |
| [[http://media.thi.ng/color/presets/yellow-magenta-cyan.svg]] | [[http://media.thi.ng/color/presets/orange-blue.svg]] |
| :yellow-magenta-cyan preset                               | :orange-blue                                      |
| [[http://media.thi.ng/color/presets/green-magenta.svg]]       | [[http://media.thi.ng/color/presets/green-red.svg]]   |
| :green-magenta                                            | :green-red                                        |
| [[http://media.thi.ng/color/presets/green-cyan.svg]]          | [[http://media.thi.ng/color/presets/blue-cyan.svg]]   |
| :green-cyan                                               | :blue-cyan                                        |
| [[http://media.thi.ng/color/presets/yellow-red.svg]]          | [[http://media.thi.ng/color/presets/red-blue.svg]]    |
| :yellow-red                                               | :red-blue                                         |

*** Implementation

The two functions below implement the gradient generation function:
=cosine-gradient-color= to compute single colors and
=cosine-gradient-scheme= to create a vector of n tuples covering the
full gradient range.

*Note:* These function are not restricted to RGB colors and can be
used in many other contexts - think of it as an ND waveform
generator...

#+BEGIN_SRC clojure :noweb-ref generators
  (defn cosine-gradient-color
    [offset amp fmod phase t]
    (col/rgba
     (mapv
      (fn [a b c d] (m/clamp (+ a (* b (Math/cos (* TWO_PI (+ (* c t) d))))) 0 1))
      offset amp fmod phase)))

  (defn cosine-gradient
    "Takes a length n and 4 cosine coefficients (for colors usually 3 or
    4-element vectors) and produces vector of n new RGBA colors, with
    each of its elements defined by an AM & FM cosine wave and clamped
    to the [0 1] interval."
    ([n spec]
     (apply cosine-gradient n spec))
    ([n offset amp fmod phase]
     (mapv #(cosine-gradient-color offset amp fmod phase %) (m/norm-range (dec n)))))
#+END_SRC

*** Example usage

#+BEGIN_SRC clojure
  ;; using a preset
  (def my-grad
    (->> :red-blue
         (grad/cosine-schemes)
         (apply grad/cosine-gradient 100)))

  ;; specifying cosine coefficients directly
  (def my-grad
    (grad/cosine-gradient 100 [0.5 0 0.5] [0.5 0 0.5] [0.5 0 0.5] [0 0 0.5]))
#+END_SRC

*** Gradient presets visualization

This following snippet is *not* part of the library and only used to
create the above preset visualizations. Requires http://thi.ng/geom to
be added to your REPL/project in order to run...

When tangling this file, the code below will be saved in the
=/babel/dev/= subdir of this project...

#+BEGIN_SRC clojure :tangle ../babel/dev/cosine-previews.clj :mkdirp yes :padline no
  (require '[thi.ng.color.core :as col])
  (require '[thi.ng.color.gradients :as grad])
  (require '[thi.ng.geom.viz.core :as viz])
  (require '[thi.ng.geom.svg.core :as svg])
  (require '[thi.ng.math.core :as m])

  (defn channel-specs
    [colors]
    (map-indexed
     (fn [idx col]
       {:values  (viz/uniform-domain-points [0 1] (map #(nth (deref %) idx) colors))
        :attribs {:fill "none" :stroke col}
        :layout  viz/svg-line-plot})
     ["red" "green" "blue"]))

  (defn color-bars
    [x1 x2 y w h colors]
    (let [n (dec (count colors))]
      (for [i (m/norm-range n)]
        (svg/rect [(m/mix* x1 x2 i) y] w h {:fill (colors (int (* i n)))}))))

  (doseq [[id coeffs] grad/cosine-schemes]
    (let [colors (grad/cosine-gradient 100 coeffs)]
      (->> {:x-axis (viz/linear-axis
                     {:domain [0 1] :range [50 580] :major 0.5 :minor 0.125 :pos 250})
            :y-axis (viz/linear-axis
                     {:domain [0 1] :range [250 20] :major 0.2 :minor 0.1 :pos 50
                      :label-dist 15 :label {:text-anchor "end"}})
            :grid   {:minor-y true}
            :data   (channel-specs colors)}
           (viz/svg-plot2d-cartesian)
           (svg/svg
            {:width 600 :height 300}
            (color-bars 50 570 280 10 20 colors))
           (svg/serialize)
           (spit (str (name id) ".svg")))))
#+END_SRC

** Complete namespace definition

#+BEGIN_SRC clojure :tangle ../babel/src/thi/ng/color/gradients.cljc :noweb yes :mkdirp yes :padline no
  (ns thi.ng.color.gradients
    #?(:cljs
    (:require-macros
     [thi.ng.math.macros :as mm]))
    (:require
     [thi.ng.math.core :as m :refer [PI TWO_PI]]
     [thi.ng.color.core :as col]
     #?(:clj [thi.ng.math.macros :as mm])))

  <<generators>>
#+END_SRC
{'fraction_non_alphanumeric': 0.15926248548199767, 'fraction_numerical': 0.06308072009291521, 'mean_word_length': 2.0041430440470998, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 38, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1828434', 'n_tokens_mistral': 5548, 'n_tokens_neox': 4856, 'n_words': 1352}