# How do I make distance between concentric circles equal?

I've been beating my head against this for a while. The reason the rings are not aligned is because I initially started the project in Photoshop.

How can I the change the distance between rings to be a uniform measurement?

This is a close-up of the rings. Right now you can see that some are closer than others.

This is a photo of the full image:

• One thing isn't clear to me: The circles have different stroke width. Do you need the same distance between the middle of each stroke or do you need the same white space between each circle. The last one is even more difficult since the diameter must take the stroke width of each circle into account. Aug 21, 2019 at 17:16

I'd say things like this are better done with automation. Imagine width of one of the items in the middle of your collection changes and you'll have to rebuild half of the circles. Or you need to make all the circles 50% more wide. Oh man!

I don't know Illustrator scripting, but in Photoshop it's quite straightforward. Basically I have a `data` array with properties like `name`, `value`, `color` and I have a function that creates a shape layer in specific coordinates with a specific radius. Plus I have several additional parameters like a gap between the circles, a maximum width of a circle and a starting radius.

Using this data, in a loop I create a circle for each data entry. Center is always a document center, width is calculated linearly based on a maximum width and a maximum data value found, radius is calculated based on a width, previous radius and a gap.

Here're different results based on different settings for a gap, starting radius and max width:

And the code I used:

``````function main()
{

//data definitions
var center = {
x: activeDocument.width.as("px") / 2,
y: activeDocument.height.as("px") / 2
};
var gap = 3; // gap between circles
var maxWidth = 15; // maximum width
var maxValue = -1; // stores maximum value found
var width, i;

var data = [
{
color: [223,41,53],
value: 22,
name: "Jerelyn Pinkbeard"
},
{
color: [65,39,34],
value: 13,
name: "Spiteful Christine Black"
},
{
color: [223,160,110],
value: 44,
name: "Generous Christi"
},
{
color: [12,243,187],
value: 4,
name: "Scrawny Tiphanie"
},
{
color: [134,186,144],
value: 12,
name: "Cutthroat Deena The Spiteful"
},
{
color: [5,47,95],
value: 22,
name: "Jerilyn Blackhate"
},
{
color: [0,83,119],
value: 60,
name: "Tiphanie Generousparrot"
},
{
color: [6,167,125],
value: 33,
name: "First Mate Christa The Scrawny"
},
{
color: [213,198,122],
value: 12,
}];

/////////////////////////////////////////////////////////////////////////////////////
// START

// first calculating maximum value of all data properties to use it later for linear transforms
for (i = 0; i < data.length; i++)
{
if (data[i].value > maxValue) maxValue = data[i].value;
}

// creating circles
for (i = 0; i < data.length; i++)
{
//calculating width lineary based on maximum value found and maximum width possible
width = linear(data[i].value, 0, maxValue, 0, maxWidth);

createCircle(
{
x: center.x, // X center of the document
y: center.y, // Y center of the document
color: data[i].color, // color from my data
width: width, // calculated width
name: data[i].name // and a name
});

startRad += width + gap; // updating starting radius with width and gap
}

function createCircle(data)
{
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putClass(sTID('contentLayer'));
desc2.putReference(cTID('null'), ref1);
var desc3 = new ActionDescriptor();
var desc4 = new ActionDescriptor();
var desc5 = new ActionDescriptor();
desc5.putDouble(cTID('Rd  '), 45.000001);
desc5.putDouble(cTID('Grn '), 77.000003);
desc5.putDouble(cTID('Bl  '), 113.000001);
desc4.putObject(cTID('Clr '), cTID('RGBC'), desc5);
desc3.putObject(cTID('Type'), sTID('solidColorLayer'), desc4);
var desc6 = new ActionDescriptor();
desc6.putUnitDouble(cTID('Top '), cTID('#Pxl'), data.y - data.radius);
desc3.putObject(cTID('Shp '), cTID('Elps'), desc6);
var desc7 = new ActionDescriptor();
desc7.putInteger(sTID('strokeStyleVersion'), 2);
desc7.putBoolean(sTID('strokeEnabled'), true);
desc7.putBoolean(sTID('fillEnabled'), false);
desc7.putUnitDouble(sTID('strokeStyleLineWidth'), cTID('#Pxl'), data.width);
desc7.putUnitDouble(sTID('strokeStyleLineDashOffset'), cTID('#Pnt'), 0.000000);
desc7.putDouble(sTID('strokeStyleMiterLimit'), 100.000000);
desc7.putEnumerated(sTID('strokeStyleLineCapType'), sTID('strokeStyleLineCapType'), sTID('strokeStyleButtCap'));
desc7.putEnumerated(sTID('strokeStyleLineJoinType'), sTID('strokeStyleLineJoinType'), sTID('strokeStyleMiterJoin'));
desc7.putEnumerated(sTID('strokeStyleLineAlignment'), sTID('strokeStyleLineAlignment'), sTID('strokeStyleAlignOutside'));
desc7.putBoolean(sTID('strokeStyleScaleLock'), false);
var list1 = new ActionList();
desc7.putList(sTID('strokeStyleLineDashSet'), list1);
desc7.putEnumerated(sTID('strokeStyleBlendMode'), cTID('BlnM'), cTID('Nrml'));
desc7.putUnitDouble(sTID('strokeStyleOpacity'), cTID('#Prc'), 100.000000);
var desc8 = new ActionDescriptor();
var desc9 = new ActionDescriptor();
desc9.putDouble(cTID('Rd  '), data.color[0]);
desc9.putDouble(cTID('Grn '), data.color[1]);
desc9.putDouble(cTID('Bl  '), data.color[2]);
desc8.putObject(cTID('Clr '), cTID('RGBC'), desc9);
desc7.putObject(sTID('strokeStyleContent'), sTID('solidColorLayer'), desc8);
desc7.putDouble(sTID('strokeStyleResolution'), 72.000000);
desc3.putObject(sTID('strokeStyle'), sTID('strokeStyle'), desc7);
desc2.putObject(cTID('Usng'), sTID('contentLayer'), desc3);
desc2.putInteger(cTID('LyrI'), 2);
executeAction(cTID('Mk  '), desc2, DialogModes.NO);

if (data.name != undefined)
{
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated(cTID("Lyr "), cTID("Ordn"), cTID("Trgt"));
desc.putReference(cTID('null'), ref);
var descName = new ActionDescriptor();
descName.putString(cTID('Nm  '), data.name);
desc.putObject(cTID('T   '), cTID('Lyr '), descName);
executeAction(cTID('setd'), desc, DialogModes.NO);
}
} // end of createCircle()

function linear(X, A, B, C, D)
{
var Y = (X - A) / (B - A) * (D - C) + C
return Y;
};

function cTID(s)
{
return app.charIDToTypeID(s);
}

function sTID(s)
{
return app.stringIDToTypeID(s);
}

}
app.activeDocument.suspendHistory("create circles", "main()");
``````
• Nice solution +1, although like the other answers, this would mean the OP would still have to start all over again, Also, wouldn't it be possible to perhaps link this script to read data from an Excel spread sheet rather than type it again? Aug 21, 2019 at 9:13
• It'd be possible to read data from a csv-file exported from Excel for example, if OP updates his answer with a sample csv I can include this step. And yes, this actually answers a different question (how to approach a task like that) rather than OP's question, but as others mentioned, I don't think it's possible to fix the existing project. Good news the script can create a new layout in seconds :) Aug 21, 2019 at 9:23
• TIL Illustrator can be scripted with JS, AppleScript or VB Script. Aug 21, 2019 at 11:32
• Instead of reading from Excel, use formulas to generate the code, e.g. ="{ color:[" & A1 & ", " & A2 ... Aug 21, 2019 at 16:54
• Where this A1 would come from? Aug 21, 2019 at 19:52

It's unfortunate that you hadn't begun your project in Illustrator. Photoshop just isn't the right kind of software for work like this since the output would be raster, not vector. I suppose you could start over again. As Scott has said, short of finding (or writing) a script, neither Illustrator nor Photoshop has any automated way of scaling concentric circles of various widths so that the gap between them is the same, after the fact.

In Illustrator it would have been easy enough to create a polar grid, and fill the cells with the Live Paint bucket.

For example:

• Select all

• Align on center vertically

• Align on center horizontally

Of course this won't alter the diameter of the circles.

If you want equidistant between each circle, then you need to use diameters that are the proper sizes.

In that case.... it may honestly be easier to start over. See here.

• I have tried to use the Align function but you're right, it doesn't create a uniform gap between circles. I have been working on this project for 3 weeks and each ring is correlated with financial data to derive its thickness. Is there no way to work with what I already have created? It would be quite the task to restart Aug 21, 2019 at 0:33
• Well it would take as much if not more work to work with what you have because you'd have to alter the diameter of each and every ring to the proper measurement to create equal spacing. I don't know of anything in Illustrator that will "auto-size" circles in a concentric fashion. You might be able to find a script somewhere for that - but again, time searching for it may be more time that it takes to simply start over. Aug 21, 2019 at 0:38
• Thanks Scott. I appreciate your help. Any place you suggest that I might be able to find the script? Aug 21, 2019 at 1:03
• Is this kind of display an effective communicator of the presented information? There are a lot of circles there and it's not apparent to me that the users who are being presented with this data will be able to quickly glean the desired understanding of the financial data and relationships. Aug 21, 2019 at 20:53

Restart in Illustrator. Make an art brush which contains a rectangular piece of each ring. Apply the brush to a circle stroke:

I drew 5 rectangles. Their widths = the wanted ring widths. They were selected all and dragged to the brushes collection. In the definition dialog I selected "Art Brush". See the definition dialog:

I drew a circle with diameter = the average diameter of the rings and applied the new brush to it. It's in the left in the first attached image.