'Random' color AI script with no adjacent colors the same
Copy link to clipboard
Copied
Could an Illustrator script like RandomSwatchesFill be modified to apply colors in such a way that no two colors from a group of swatches would be repeated in shapes that immediately border each other? I don't think this is truly random, but it's meant to make the distribution of colors feel more varied.
From what I've seen online, this would be an application of the four color theorem — or whatever number of colors are involved. For my own purposes, I would typically have more colors in a group of swatches — at least five or more.
Appreciate any insights and guidance!
Explore related tutorials & articles
Copy link to clipboard
Copied
Firstly, you'll need to define what "adjacent" means in terms of path items in Illustrator.
Copy link to clipboard
Copied
By adjacent, I mean shapes that immediately border each other. In my case, the simplest example might be a checkerboard-like grid where colors are assigned so that no squares that border each other are colored the same. Thanks.
Copy link to clipboard
Copied
It could be done using an adjacency matrix, but I'm not familiar with implementing graphs in JS.
Copy link to clipboard
Copied
On second thought, for the simplest case (as you describe), no adjacency matrix is required. A usual matrix used to compare the color of a path item with that of the path items above and to the left will suffice.
// run in CMYK color mode
var f = 2.83465;
var string1 = prompt("Enter rows-space-columns", "10 10");
var splitString1 = string1.split(" ");
var rows = Number(splitString1[0]), columns = Number(splitString1[1]);
var ABRect = app.activeDocument.artboards[0].artboardRect;
var paths = app.activeDocument.pathItems;
var w = h = 20 * f, sumW = w * rows, sumH = h * columns;
var top = ABRect[3] / 2 + sumH / 2;
for (var i = 0; i < columns; i++) {
var left = ABRect[2] / 2 - sumW / 2;
for (var j = 0; j < rows; j++) {
var rect0 = paths.rectangle(top, left, w, h);
left = left + w;
}
top = top - h;
}
// create matrix
var x = rows * columns - 1;
var matrix = [];
for (var i = 0; i < rows; i++) {
matrix[i] = [];
for (var j = 0; j < columns; j++) {
matrix[i][j] = paths[x];
x = x - 1;
}
}
// compare color of pathItem to color of pathItems above and to left
var swatchez = app.activeDocument.swatches;
var c = swatchez["CMYK Cyan"].color, m = swatchez["CMYK Magenta"].color,
y = swatchez["CMYK Yellow"].color, k = swatchez["Black"].color;
for (var i = 0; i < rows; i++) {
for (var j = 0; j < columns; j++) {
var colorz = [{value:c, name:"c"}, {value: m, name:"m"}, {value: y, name:"y"}, {value: k, name:"k"}];
for (var l = colorz.length - 1; l > -1 ; l--) {
var color = colorz[l].value;
if ((i > 0) && (color.cyan == matrix[i-1][j].fillColor.cyan && color.magenta == matrix[i-1][j].fillColor.magenta && color.yellow == matrix[i-1][j].fillColor.yellow && color.black == matrix[i-1][j].fillColor.black)) {
colorz.splice(l, 1);
}
if ((j > 0) && (color.cyan == matrix[i][j-1].fillColor.cyan && color.magenta == matrix[i][j-1].fillColor.magenta && color.yellow == matrix[i][j-1].fillColor.yellow && color.black == matrix[i][j-1].fillColor.black)) {
colorz.splice(l, 1);
}
}
var index = Math.floor(Math.random() * colorz.length);
matrix[i][j].fillColor = colorz[index].value;
}
}
Copy link to clipboard
Copied
This is a first attempt at implementing of a graph using an adjacency list:
You will need a list of "edges" to enter into a text box when running the script. A graph is a group of vertices (or nodes), which in our case represent paths, connected to each other by edges (or links), which in our case represent shared borders. An edge is defined by the two vertices it connects.
In the picture below, the paths on the left are represented by the graph on the right. Each line is an edge. For example, path1 shares a border with path2 and path3. This is represented by the two edges "path1, path2" and "path1, path3". You will need a list of all these edges.
This is a very frivolous implementation. In fact, there's a bug I haven't fixed: With more edges, there is a chance (about 1/10) that >4 colors will be needed.
// instructions
// (1) name your paths
// (2) have a list of edges ready to input
// (3) an edge is a pair of path names separated by a comma
// (4) run in CMYK mode (or change the "color" part of the script to run in RGB mode)
// (5) select your paths and run
// input
var vertices = [];
for (var i = 0; i < selection.length;i++) {
vertices.push(selection[i].name);
}
var test =
"path1, path2\
path1, path3\
path2, path3\
path2, path4\
path2, path5\
path3, path5\
path3, path6\
path4, path5\
path5, path6";
var w = new Window ("dialog", "Edges");
var text1 = w.add ("edittext", [0, 0, 150, 140], "", {multiline: true, wantReturn: true});
text1.text = test;
w.add ("button", undefined, "OK");
w.show ();
var edges = text1.text.split("\n");
for (var i = 0; i < edges.length; i++) {
edges[i] = edges[i].split(", ");
}
// create graph (adjacency list)
var list = {};
for (var i = 0; i < vertices.length; i++) {
list[vertices[i]] = [];
}
for (var i = 0; i < edges.length; i++) {
list[edges[i][0]].push(edges[i][1]);
list[edges[i][1]].push(edges[i][0]);
}
// color
var paths = app.activeDocument.pathItems;
var swatchez = app.activeDocument.swatches;
var c = swatchez["CMYK Cyan"].color,
m = swatchez["CMYK Magenta"].color,
y = swatchez["CMYK Yellow"].color,
k = swatchez["Black"].color;
for (var key in list) {
var colorz = [c, m, y, k];
for (var i = 0; i < list[key].length; i++) {
for (var l = colorz.length - 1; l > -1 ; l--) {
var c1 = colorz[l];
var c2 = paths[list[key][i]].fillColor;
if (c1.cyan == c2.cyan && c1.magenta == c2.magenta &&
c1.yellow == c2.yellow && c1.black == c2.black) {
colorz.splice(l, 1);
}
}
}
var index = Math.floor(Math.random() * colorz.length);
if (!colorz[index]) {
paths[key].fillColor = swatchez["White"].color;
} else {
paths[key].fillColor = colorz[index];
}
}
Copy link to clipboard
Copied
That is pretty wicked, even as a demo! If I understand your implementation, for more complex figures, you would need to input values that help define the relative positions of each 'cell.'
Running the script now creates its own matrix. Would it be able to fill a custom-designed figure?
Appreciate your exploration.
Copy link to clipboard
Copied
"... for more complex figures, you would need to input values that help define the relative positions of each 'cell.'"
Correct.
"Running the script now creates its own matrix. Would it be able to fill a custom-designed figure?"
Do you mean fill a path with the chequered pattern? You could manually convert the outcome of the first script into a pattern and apply it to a path. I suppose you could do it with a script, but again I have not done patterns with scripting.
Copy link to clipboard
Copied
Hi @femkeblanco, this is cool stuff! Thanks for sharing.
- Mark
Copy link to clipboard
Copied
Thanks, @m1b. I do think graphs are interesting and potentially useful in Illustrator scripting, but, regrettably, like many other things, I don't have the time to learn them. If you're interested, there is a very basic short chapter on graphs in the book "Data Structures and Algorithms with JavaScript" by Michael McMillan.

