Skip to content

Commit

Permalink
Config: Add randomSeed
Browse files Browse the repository at this point in the history
  • Loading branch information
Stukova committed Dec 7, 2022
1 parent 67f2321 commit 1ce34f8
Show file tree
Hide file tree
Showing 11 changed files with 64 additions and 13 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ graph.setData(nodes, links)
| showFPSMonitor | Show WebGL performance monitor | `false`
| pixelRatio | Canvas pixel ratio | `2`
| scaleNodesOnZoom | Scale the nodes when zooming in or out | `true`
| randomSeed | Providing a `randomSeed` value allows you to control the randomness of the layout across different simulation runs. It is useful when you want the graph to always look the same on same datasets. <br /><br /> This property will be applied only on component initialization and it can't be changed using the `setConfig` method. | `undefined`


### <a name="simulation_configuration" href="#simulation_configuration">#</a> Simulation configuration
Expand Down
30 changes: 30 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"d3-zoom": "^3.0.0",
"gl-bench": "^1.0.42",
"gl-matrix": "^3.4.3",
"random": "^4.1.0",
"regl": "^2.1.0"
},
"pre-commit": "lint:staged",
Expand Down
11 changes: 11 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,15 @@ export interface GraphConfigInterface<N extends InputNode, L extends InputLink>
* Default value: true
*/
scaleNodesOnZoom?: boolean;
/**
* Providing a `randomSeed` value allows you to control
* the randomness of the layout across different simulation runs.
* It is useful when you want the graph to always look the same on same datasets.
* This property will be applied only on component initialization and it
* can't be changed using the `setConfig` method.
* Default value: undefined
*/
randomSeed?: number | string;
}

export class GraphConfig<N extends InputNode, L extends InputLink> implements GraphConfigInterface<N, L> {
Expand Down Expand Up @@ -303,6 +312,8 @@ export class GraphConfig<N extends InputNode, L extends InputLink> implements Gr

public scaleNodesOnZoom = defaultConfigValues.scaleNodesOnZoom

public randomSeed = undefined

public init (config: GraphConfigInterface<N, L>): GraphConfigInterface<N, L> {
const currentConfig = this.getConfig()
const keys = Object.keys(config).map(key => key as keyof GraphConfigInterface<N, L>)
Expand Down
4 changes: 0 additions & 4 deletions src/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,6 @@ export function group <ArrayItem, Key> (array: ArrayItem[], accessor: (d: ArrayI
return groups
}

export function getRandomValue (min: number, max: number): number {
return Math.random() * (max - min) + min
}

export function clamp (num: number, min: number, max: number): number {
return Math.min(Math.max(num, min), max)
}
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ export class Graph<N extends InputNode, L extends InputLink> {
this.store.backgroundColor = getRgbaColor(this.config.backgroundColor)

if (this.config.showFPSMonitor) this.fpsMonitor = new FPSMonitor(this.canvas)

if (this.config.randomSeed !== undefined) this.store.addRandomSeed(this.config.randomSeed)
}

public get progress (): number {
Expand Down
2 changes: 1 addition & 1 deletion src/modules/ForceLink/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class ForceLink<N extends InputNode, L extends InputLink> extends CoreMod
strength = Math.sqrt(strength)
linkBiasAndStrengthState[linkIndex * 4 + 0] = bias
linkBiasAndStrengthState[linkIndex * 4 + 1] = strength
linkDistanceState[linkIndex * 4] = Math.random() // link distance random variation
linkDistanceState[linkIndex * 4] = this.store.getRandomFloat(0, 1)

linkIndex += 1
})
Expand Down
5 changes: 2 additions & 3 deletions src/modules/ForceManyBody/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import clearFrag from '@/graph/modules/Shared/clear.frag'
import updateVert from '@/graph/modules/Shared/quad.vert'
import { defaultConfigValues } from '@/graph/variables'
import { InputNode, InputLink } from '@/graph/types'
import { getRandomValue } from '@/graph/helper'

export class ForceManyBody<N extends InputNode, L extends InputLink> extends CoreModule<N, L> {
private randomValuesFbo: regl.Framebuffer2D | undefined
Expand Down Expand Up @@ -37,8 +36,8 @@ export class ForceManyBody<N extends InputNode, L extends InputLink> extends Cor
// Create random number to prevent point to stick together in one coordinate
const randomValuesState = new Float32Array(store.pointsTextureSize * store.pointsTextureSize * 4)
for (let i = 0; i < store.pointsTextureSize * store.pointsTextureSize; ++i) {
randomValuesState[i * 4] = getRandomValue(-1, 1) * 0.00001
randomValuesState[i * 4 + 1] = getRandomValue(-1, 1) * 0.00001
randomValuesState[i * 4] = store.getRandomFloat(-1, 1) * 0.00001
randomValuesState[i * 4 + 1] = store.getRandomFloat(-1, 1) * 0.00001
}

this.randomValuesFbo = reglInstance.framebuffer({
Expand Down
5 changes: 2 additions & 3 deletions src/modules/ForceManyBodyQuadtree/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import clearFrag from '@/graph/modules/Shared/clear.frag'
import updateVert from '@/graph/modules/Shared/quad.vert'
import { defaultConfigValues } from '@/graph/variables'
import { InputNode, InputLink } from '@/graph/types'
import { getRandomValue } from '@/graph/helper'

export class ForceManyBodyQuadtree<N extends InputNode, L extends InputLink> extends CoreModule<N, L> {
private randomValuesFbo: regl.Framebuffer2D | undefined
Expand Down Expand Up @@ -37,8 +36,8 @@ export class ForceManyBodyQuadtree<N extends InputNode, L extends InputLink> ext
// Create random number to prevent point to stick together in one coordinate
const randomValuesState = new Float32Array(store.pointsTextureSize * store.pointsTextureSize * 4)
for (let i = 0; i < store.pointsTextureSize * store.pointsTextureSize; ++i) {
randomValuesState[i * 4] = getRandomValue(-1, 1) * 0.00001
randomValuesState[i * 4 + 1] = getRandomValue(-1, 1) * 0.00001
randomValuesState[i * 4] = store.getRandomFloat(-1, 1) * 0.00001
randomValuesState[i * 4 + 1] = store.getRandomFloat(-1, 1) * 0.00001
}

this.randomValuesFbo = reglInstance.framebuffer({
Expand Down
6 changes: 4 additions & 2 deletions src/modules/Points/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ export class Points<N extends InputNode, L extends InputLink> extends CoreModule
const sortedIndex = this.data.getSortedIndexByInputIndex(i)
const node = data.nodes[i]
if (node && sortedIndex !== undefined) {
initialState[sortedIndex * 4 + 0] = node.x ?? (spaceSize ?? defaultConfigValues.spaceSize) * (Math.random() * (0.505 - 0.495) + 0.495)
initialState[sortedIndex * 4 + 1] = node.y ?? (spaceSize ?? defaultConfigValues.spaceSize) * (Math.random() * (0.505 - 0.495) + 0.495)
initialState[sortedIndex * 4 + 0] = node.x ??
(spaceSize ?? defaultConfigValues.spaceSize) * (store.getRandomFloat(0, 1) * (0.505 - 0.495) + 0.495)
initialState[sortedIndex * 4 + 1] = node.y ??
(spaceSize ?? defaultConfigValues.spaceSize) * (store.getRandomFloat(0, 1) * (0.505 - 0.495) + 0.495)
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/modules/Store/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { scaleLinear } from 'd3-scale'
import { mat3 } from 'gl-matrix'
import { Random } from 'random'

export const ALPHA_MIN = 0.001
export const MAX_POINT_SIZE = 64
Expand All @@ -21,6 +22,15 @@ export class Store {
private alphaTarget = 0
private scaleNodeX = scaleLinear()
private scaleNodeY = scaleLinear()
private random = new Random()

public addRandomSeed (seed: number | string): void {
this.random = this.random.clone(seed)
}

public getRandomFloat (min: number, max: number): number {
return this.random.float(min, max)
}

public updateScreenSize (width: number, height: number, spaceSize: number): void {
this.screenSize = [width, height]
Expand Down

0 comments on commit 1ce34f8

Please sign in to comment.