Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

'Random' color AI script with no adjacent colors the same

Community Beginner ,
Jan 04, 2021 Jan 04, 2021

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!

TOPICS
Draw and design , Feature request , Scripting , Third party plugins
1.5K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Adobe
Guide ,
Jan 06, 2021 Jan 06, 2021

Firstly, you'll need to define what "adjacent" means in terms of path items in Illustrator.  

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Jan 09, 2021 Jan 09, 2021

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.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Jan 10, 2021 Jan 10, 2021

It could be done using an adjacency matrix, but I'm not familiar with implementing graphs in JS. 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Feb 27, 2021 Feb 27, 2021

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.

Untitled99.pngexpand image

 

// 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;
    }
}

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Mar 22, 2021 Mar 22, 2021

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. 

 

G1.jpgexpand image

 

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. 

 

G2.jpgexpand image

 

G3.jpgexpand image

 

Test.ai file 

 

// 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];
    }
}

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Beginner ,
Mar 22, 2021 Mar 22, 2021

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.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
Mar 24, 2021 Mar 24, 2021

"... 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.  

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Community Expert ,
May 06, 2022 May 06, 2022

Hi @femkeblanco, this is cool stuff! Thanks for sharing.

- Mark

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
Guide ,
May 06, 2022 May 06, 2022
LATEST

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.

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines