Skip to content

Instantly share code, notes, and snippets.

@jelder
Created May 2, 2024 18:31
Show Gist options
  • Save jelder/4c41b326612de21f15bc0f7b030eaed9 to your computer and use it in GitHub Desktop.
Save jelder/4c41b326612de21f15bc0f7b030eaed9 to your computer and use it in GitHub Desktop.
import hashlib
class NodeColor:
"""
Assign a random but deterministic color to a string, suitable for coloring a graph.
"""
def __init__(self, tag):
self.hue = self.__get_hue(tag)
def __get_hue(self, tag):
"""
In HSL space, the hue represents the color itself as an angle on the
color wheel, where red is both 0° and 360° and cyan is at 180°. We use a
hash function to map the tag to a hue. This is deterministic, so the
same tag will always get the same hue.
This uses `hashlib.sha256`, which is available in the Python standard
library. Some of the values I've seen in this project are subjectively a
little close together, and MurmurHash3 would be a beter choice.
We then convert the hue to a value between 0 and 1, which is the format
used by GraphViz.
"""
hash_object = hashlib.sha256(tag.encode())
hash_value = int(hash_object.hexdigest(), 16)
return hash_value % 1000 / 1000
def format(self, h, s, l):
"""
See https://graphviz.org/docs/attr-types/color/
"""
return '"{:02} {:02} {:02}"'.format(h, s, l)
def edge(self):
"""
Returns a color as hue/saturation/value in floating point format for
GraphViz.
Edge colors are more saturated than fill colors. Here "edge" means both
the border of the node and the lines connecting nodes.
"""
return self.format(self.hue, 0.80, 0.75)
def fill(self):
"""
Returns a color as hue/saturation/value in floating point format for
GraphViz.
Fill colors are less saturated than edge colors.
"""
return self.format(self.hue, 0.30, 0.75)
def text(self):
"""
Returns a color as hue/saturation/value in floating point format for
GraphViz.
Text colors have a low lightness to contrast with the fill color, but
the same high saturation as the edge color.
"""
return self.format(self.hue, 0.80, 0.35)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment