|
- // Copyright 2023 The casbin Authors. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- package object
-
- import (
- "fmt"
- "image/color"
- "math"
- "strconv"
-
- "github.com/casibase/casibase/util"
- )
-
- var graphCache map[string]*Graph
-
- func init() {
- graphCache = map[string]*Graph{}
- }
-
- func GetWordsetGraph(id string, clusterNumber int, distanceLimit int) (*Graph, error) {
- cacheId := fmt.Sprintf("%s|%d|%d", id, clusterNumber, distanceLimit)
-
- g, ok := graphCache[cacheId]
- if ok {
- return g, nil
- }
-
- wordset, err := GetWordset(id)
- if err != nil {
- return nil, err
- }
- if wordset == nil {
- return nil, nil
- }
-
- if len(wordset.Factors) == 0 {
- return nil, nil
- }
-
- allZero := true
- for _, factor := range wordset.Factors {
- if len(factor.Data) != 0 {
- allZero = false
- break
- }
- }
- if allZero {
- return nil, nil
- }
-
- runKmeans(wordset.Factors, clusterNumber)
-
- g = generateGraph(wordset.Factors, distanceLimit)
- // graphCache[cacheId] = g
- return g, nil
- }
-
- func getDistance(v1 *Factor, v2 *Factor) float64 {
- res := 0.0
- for i := range v1.Data {
- res += (v1.Data[i] - v2.Data[i]) * (v1.Data[i] - v2.Data[i])
- }
- return math.Sqrt(res)
- }
-
- func refineFactors(factors []*Factor) []*Factor {
- res := []*Factor{}
- for _, factor := range factors {
- if len(factor.Data) > 0 {
- res = append(res, factor)
- }
- }
- return res
- }
-
- func getNodeColor(weight int) string {
- if weight > 10 {
- weight = 10
- }
- f := (10.0 - float64(weight)) / 10.0
-
- color1 := color.RGBA{R: 232, G: 67, B: 62}
- color2 := color.RGBA{R: 24, G: 144, B: 255}
- myColor := util.MixColor(color1, color2, f)
- return fmt.Sprintf("rgb(%d,%d,%d)", myColor.R, myColor.G, myColor.B)
- }
-
- func generateGraph(factors []*Factor, distanceLimit int) *Graph {
- factors = refineFactors(factors)
- // factors = factors[:100]
-
- g := newGraph()
- g.Nodes = []*Node{}
- g.Links = []*Link{}
-
- nodeWeightMap := map[string]int{}
- for i := 0; i < len(factors); i++ {
- for j := i + 1; j < len(factors); j++ {
- v1 := factors[i]
- v2 := factors[j]
- distance := int(getDistance(v1, v2))
- if distance >= distanceLimit {
- continue
- }
-
- if v, ok := nodeWeightMap[v1.Name]; !ok {
- nodeWeightMap[v1.Name] = 1
- } else {
- nodeWeightMap[v1.Name] = v + 1
- }
- if v, ok := nodeWeightMap[v2.Name]; !ok {
- nodeWeightMap[v2.Name] = 1
- } else {
- nodeWeightMap[v2.Name] = v + 1
- }
-
- linkValue := (1*(distance-7) + 10*(distanceLimit-1-distance)) / (distanceLimit - 8)
- linkColor := "rgb(44,160,44,0.6)"
- linkName := fmt.Sprintf("Edge [%s] - [%s]: distance = %d, linkValue = %d", v1.Name, v2.Name, distance, linkValue)
- fmt.Println(linkName)
- g.addLink(linkName, v1.Name, v2.Name, linkValue, linkColor, strconv.Itoa(distance))
- }
- }
-
- for _, factor := range factors {
- // value := 5
- value := int(math.Sqrt(float64(nodeWeightMap[factor.Name]))) + 3
- weight := nodeWeightMap[factor.Name]
-
- // nodeColor := "rgb(232,67,62)"
- // nodeColor := getNodeColor(value)
- nodeColor := factor.Color
-
- fmt.Printf("Node [%s]: weight = %d, nodeValue = %d\n", factor.Name, nodeWeightMap[factor.Name], value)
- g.addNode(factor.Name, factor.Name, value, nodeColor, factor.Category, weight)
- }
-
- return g
- }
|