Last active
December 19, 2019 23:43
-
-
Save basgys/68c06269e6961b76be6ad585606c09e1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"math" | |
"sort" | |
"strings" | |
"github.com/pbnjay/clustering" | |
) | |
type Palette struct { | |
Name string | |
Colours map[string]string | |
} | |
type reference struct { | |
P *Palette | |
Count int | |
} | |
func main() { | |
palettes := []*Palette{ | |
{ | |
Name: "colours", | |
Colours: map[string]string{ | |
"tomato": "#FF1212", | |
"apple": "#11DD22", | |
}, | |
}, | |
{ | |
Name: "brand", | |
Colours: map[string]string{ | |
"brand": "#001122", | |
"brand-light": "#112233", | |
}, | |
}, | |
{ | |
Name: "grey", | |
Colours: map[string]string{ | |
"light": "#DDDDDD", | |
"dark": "#121212", | |
}, | |
}, | |
{ | |
Name: "aggregated", | |
Colours: map[string]string{ | |
"ligher": "grey--light", | |
"light": "brand--brand", | |
"dark": "grey--dark", | |
"darker": "interactions--button-primary", | |
"apple": "colours--apple", | |
}, | |
}, | |
{ | |
Name: "interactions", | |
Colours: map[string]string{ | |
"button-primary": "brand--brand", | |
"button-danger": "colours--tomato", | |
"button-positive": "colours--apple", | |
"button-other": "colours--apple", | |
}, | |
}, | |
{ | |
Name: "notifications", | |
Colours: map[string]string{ | |
"danger": "colours--tomato", | |
"positive": "colours--apple", | |
"other": "colours--apple", | |
}, | |
}, | |
} | |
// Build colours index (colour -> palette) | |
colours := map[string]string{} | |
for _, p := range palettes { | |
for ck := range p.Colours { | |
name := strings.Join([]string{p.Name, ck}, "--") | |
colours[name] = p.Name | |
} | |
} | |
// Build distance matrix & ref counter | |
mref := map[string]*reference{} | |
dmap := clustering.DistanceMap{} | |
for i := range palettes { | |
cmap := map[clustering.ClusterItem]float64{} | |
a := palettes[i].Name | |
dmap[a] = cmap | |
mref[a] = &reference{P: palettes[i]} | |
for j := range palettes { | |
b := palettes[j].Name | |
cmap[b] = math.MaxInt8 // Add distance between the two vertices | |
} | |
} | |
// Populate matrix | |
for _, p := range palettes { | |
for _, cv := range p.Colours { | |
other, ok := colours[cv] | |
if !ok { | |
continue // Not a pointer to another colour | |
} | |
// Inc palettes ref counter | |
mref[p.Name].Count++ | |
mref[other].Count++ | |
// Reduce distance as we add a new reference | |
dmap[p.Name][other]-- | |
} | |
} | |
// Cluster palettes | |
clusters := clustering.NewDistanceMapClusterSet(dmap) | |
chk := clustering.MaxClusters(len(palettes) / 2) | |
clustering.Cluster(clusters, chk, clustering.CompleteLinkage()) | |
// Enumerate clusters and print palettes | |
debug("\nClusters") | |
clusters.EachCluster(-1, func(cluster int) { | |
clusters.EachItem(cluster, func(x clustering.ClusterItem) { | |
debug(cluster, x) | |
}) | |
}) | |
// Output(ish): | |
// | |
// 0 colours | |
// 0 brand | |
// 0 notifications | |
// 1 aggregated | |
// 1 interactions | |
// 2 grey | |
// Get ref counter and sort it | |
refs := make([]*reference, 0, len(palettes)) | |
for _, ref := range mref { | |
refs = append(refs, ref) | |
} | |
sort.Slice(refs, func(i, j int) bool { return refs[i].Count > refs[j].Count }) | |
debug("\nMost referenced palettes") | |
for _, ref := range refs { | |
debug(ref.P.Name, ref.Count) | |
} | |
// Output: | |
// | |
// colours 7 | |
// aggregated 5 | |
// interactions 5 | |
// notifications 3 | |
// brand 2 | |
// grey 2 | |
} | |
func debug(v ...interface{}) { | |
fmt.Println(v...) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment