# How to sort words alphabetically from a String?

Hey Chrisir,
Thank you very much for your help.
I’m fine too, except people here in Paris don’t wear any mask nor gloves?!

When you tell use the formula:

``````x= cos(angle) * r + centerX
y= sin(angle) * r + centerY
``````

you mean:

``````posX = cos(theta * angleFact) * r + width/2;
posY = sin(theta * angleFact) * r + height/2;
``````

map to increase radius with posY ?
Like:
r=map(posY, height/2, height, 50, 50+120*(lines.length) ?!!
Sorry I managed somehow with a bit of trigonometry, but now I’m a bit lost!!
Thanks a lot.
Take care,
L

1 Like

Hello

sorry I overlooked this

This sounds correct!!

Dear Chrisir,
It only sounds correct… But I did this below. I simplified the code and tried to get radius and angle proportionnal to posY!
The 1rst line doesn’t move, don’t know how come?!
Thanks in advance for your help, as usual Take care,
L

``````import java.util.Map;
PFont font;
String alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜß,.;:!? ";
String[]lines={
"folly folly for to",
"for to what is the word",
"folly from this all this, folly from all this",
};
int typeSize;
int x=0;
int y=0;
float r = 100;
String joinedText;
float interY;
char currentChar;
float w;
//int posX = 0;
// Note the HashMap's "key" is a String and "value" is an Integer
HashMap<String, Integer> hmYPos = new HashMap<String, Integer>();

//********************************************************************************************************************************************************

void setup() {
size(1000, 1000);
font = createFont("helvetica", 10);
textFont(font);
float ts=10;
textSize(ts);
//textAlign(CENTER);
joinedText=join(lines, " ");
prepare();
}

//********************************************************************************************************************************************************

void draw() {
background(0);
translate (width/2, height/2);
smooth();
float posX = 0;
float posY = 0;
float arcLength=0;
scale(0.20);
int lineDist= 20;

// loop over the lines
for (int j = 0; j < lines.length; j++) {
//Calculate the number of words per sentence making array with the words in that line
String[]wordsInThatLine = split(lines[j], " ");
for (int j2 = 0; j2 < wordsInThatLine.length; j2++) {
arcLength+=20;

//*****************************Arranging each char into concentric circles**********************************
int index= hmYPos.get(wordsInThatLine[j2]);
if (index<0) continue;

if ( j<=lines.length) {
r=map(posY, height/2, height, 30*j+30, 100+300*lines.length);
}
float sortY=0;
sortY = hmYPos.get(wordsInThatLine[j2])*j*2;
// getting mouse pos
float m=map(mouseX, 0, width, 0, 1);
m = constrain(m, 0, 1);
interY = lerp(posY, sortY, m);
// loop over the words in that line

for (int j3 = 0; j3 < wordsInThatLine[j2].length(); j3++) {
String s=str(wordsInThatLine[j2].charAt(j3));
currentChar= wordsInThatLine[j2].charAt(j3);
w=textWidth(currentChar);
arcLength+=w/2+10;
float theta = PI+arcLength/r;
theta += map(posY, height/2, height, TWO_PI, TWO_PI*lines.length);
pushMatrix();
rotate(-PI/2);
translate(r*cos(theta), r*sin(theta));
rotate(theta+PI/2);
noStroke();
fill(255);
float SText = hmYPos.get(wordsInThatLine[j2])*0.15+30;
textSize(SText+20);
text(currentChar, posX, interY);
popMatrix();

arcLength +=w/2;
if ( currentChar==' ') {
arcLength+=10;
}
}
//***********************************************************************************************************
}
}
}

//func

//------------------------------------------------------------

void prepare() {
HashMap<String, Integer> hm1 = new HashMap<String, Integer>();
String allLinesAsString;
String[] lines2;
String[] words={};
String[] wordsList2;

// Init hm1
// we create a parallel list to wordsList : wordsList2
wordsList2 = split(join(lines, " "), " ");
for (String s : wordsList2) {
//Putting key(String)-value(Integer) pairs in the HashMap
hm1.put(s.toLowerCase().trim(), 0); // all 0
}
// We group all the lines in a single String
allLinesAsString = join(lines, " ");
// We split the group again
lines2=split(allLinesAsString, " ");

// Counting (occurences in hm1)
for (int i=0; i<lines2.length; i++) {
String word = lines2[i].toLowerCase().trim();
if (hm1.get(word) != null) {
// here we fill hm1 if it's not equal to null
hm1.put(word, ((int) (hm1.get(word)))+1);  // add 1
}
}

//// Using an enhanced loop to iterate over each entry of hm1
for (Map.Entry me : hm1.entrySet()) {
// copy hm1 to words
words = (String[]) append (words, me.getKey());
}//for

words=sort(words);

// simulate output and save the line number for each word in sorted position
int posY=20;

for (String s : words) {
hmYPos.put( s, posY);
posY+=20;
}
}//
``````

Hello,

Check out this topic:

I was able to modify my code example to generate this:

`:)`

2 Likes

Hi @glv,
Thank you very much for your message and your help. I tried your solution in a sketch apart, now I’ll
incoporate it into my sketch and will let you know if I managed ;))
It was one problem the 2nd is that the Strings (line 1) at the center of my composition don’t move
according to posY, maybe both will be solved, hopefully Hello,

I was just sharing… you inspired me to try this.
There are many ways to do things and I just threw this together quickly.

Give consideration to text alignment.
I used in my example:
`textAlign(CENTER, CENTER);`

This may not be directly related but shows how text alignment can be a consideration:

Stay well!

`:)`

2 Likes

Hi @glv,
sorry for not replying earlier but I had a lot to do…
Thank you very much for sharing this code too! Cool!
In my attempt the letters are oriented, and also evenly distributed,
my problem stays the same, my posY coordinates!
My words are sorted according to the alphabet order and they move according to this index, but not
as it should since I pass world coordinates (y) and not polar coordinates… Why are you passing world coordinates at all? Is it external data? Can you throw it away and just start from polar?

A hand-drawing of what you want your final output to look like might be helpful.

1 Like

Hey @jeremydouglass,

Thanks a lot for your reply and questions, I’ll make a drawing of my final output to show what id’ like to acheive!

Best,

Laurent

1 Like

Dear Jeremy,
Here is the final output I’d like to obtain…!

Now i manage to get the result but not the unsorted text of the beginning…!?
Thanks a lot for your hello
Take care,
L

Got it! And currently, what does your bad output look like? What is wrong with it?

1 Like

I was looking at your code posted from 9 days ago, just trying to understand what is working for you and what is not working for you.

Hey Jeremy,
I 've sold the problem* at last! (Instead of posY I needed to pass the polar coordinates according to radius). But I have a new one*: I wonder why my bezier curves don’t link between the same letters: A with A, B with B and so on?!
Should I create a letter class to pass each letter its coordinates ? letters[i].x, letters[i].y ?!
Thanks a lot four help.
Take care,
L

``````import java.util.Map;

PFont font;

String[]lines={
"folly folly for to for to",
"what is the word",
"folly from this all this folly from all this",
"given folly given all this seeing folly seeing all this this",
"what is the word",
"this this this this here all this this here folly given all this",
"seeing folly seeing all this this here for to",
"what is the word",
"see glimpse seem to glimpse need to seem to glimpse folly for to need to seem to glimpse what",
"what is the word",
"and where folly for to need to seem to glimpse what where where what is the word there over there away over there",
"afar afar away over there",
"afaint afaint afar away over there what what",
"what is the word",
"seeing all this all this this all this this here folly for to see what glimpse seem to glimpse need to seem to glimpse",
"afaint afar away over there what",
"folly for to need to seem to glimpse afaint afar away over there what",
"what",
"what is the word",
"what is the word"
};

// --------------------------------------------------------

String[] lines2;
String[] c1={};
String[] wordsList2;
int Size;
float r = 40;
float angle = 0;

float interY;
// Note the HashMap's "key" is a String and "value" is an Integer
HashMap<String, Integer> hmYPos = new HashMap<String, Integer>();

//********************************************************************************************************************************************************

void setup() {
size(1400, 1400);
font = createFont("helvetica", 20);
textFont(font);
textAlign(CENTER);
prepare();
}

//********************************************************************************************************************************************************

void draw() {
background(0);
translate (width/2, height/2);
smooth();
scale(0.7);
float posX = 0;
float arcLength=0;
float posY = 0;
for (int j = 0; j < lines.length; j++) {
if ( j<=lines.length) {
r=45*(j+1);
}

String[]wordsInThatLine = split(lines[j], " ");
for (int j2 = 0; j2 < wordsInThatLine.length; j2++) {
int index = hmYPos.get(wordsInThatLine[j2]);

if (index<0) continue;
arcLength+=15;
mouseX=constrain(mouseX, width/2, width);
//float sortY = hmYPos.get(wordsInThatLine [j2]);
float sortY = 0;
r= map(mouseX, width/2, width, 75+45*j+1, 150+hmYPos.get(wordsInThatLine [j2]));
sortY=r;
float m=map(mouseX, width/2, width, 0, 1);
m = constrain(m, 0, 1);
interY = lerp(posY, sortY, m);

for (int j3 = 0; j3 < wordsInThatLine[j2].length(); j3++) {
char currentChar= wordsInThatLine[j2].charAt(j3);
float w=textWidth(currentChar);
arcLength+=w+5;
float theta =PI+arcLength/r;

pushMatrix();
translate(r*cos(theta), r*sin(theta));
scale(0.7);
rotate(theta+PI/2);
noFill();
stroke(181, 157, 0, 250);
strokeWeight(1);
bezier(posX, posY, currentChar, currentChar, currentChar,hmYPos.get(wordsInThatLine [j2]), posX, interY);
//bezier(0, j3, 0,j2,j,hmYPos.get(wordsInThatLine[j2]),0, 0);
noFill();
strokeWeight(2);
stroke(0, 50, 220, 200);
ellipse(0, 0, 20, 20);
fill(255, 200);
textAlign(CENTER, BASELINE);
float SText = hmYPos.get(wordsInThatLine[j2])*0.03;
textSize(SText+20);
text(currentChar, 0, 0);
popMatrix();
arcLength+=w/2;
}
}
}
}

//------------------------------------------------------------

void prepare() {
HashMap<String, Integer> hm1 = new HashMap<String, Integer>();
String message;

message= join(lines, " "); // Join all the separated strings
lines2=split(message, ",");// Split them into sentences according to the comas
// Now we have a copy of the whole text

// Init
wordsList2 = split(join(lines, " "), " "); // We do the same than above for a new copy to initialize the HashMap
for (String s : wordsList2) {              // We loop across the whole list of strings
hm1.put(s.toLowerCase(), 0);             // We fill the HashMap (hm1) and put the strings to lowerCase and put all at 0
textSize(abs(hm1.get(s)*5+Size)+15);     // We pass a textSize
}

// Counting
for (int i=0; i<lines2.length; i++) {           // We loop across the whole strings
String word = lines2[i].toLowerCase().trim(); // We put the strings to lowerCase and get rid of comas, points, etc.
if (hm1.get(word) != null) {                  // If the HashMap is not null
hm1.put(word, ((int) (hm1.get(word)))+1);   // We fill the HashMap with the 2nd list of strings (word) and we add 1
}
}

//// Using an enhanced loop to iterate over each entry
for (Map.Entry me : hm1.entrySet()) {
c1 = (String[]) append (c1, me.getKey());
}//for
c1=sort(c1); //We sort the strings according to the alphabet
println(c1);

// simulate output and save the line number for each word in sorted position
int posY=0;
for (String s : c1) {
hmYPos.put( s, posY);
//Size=hmYPos.get(s);
posY += 25;
}
}//
//
``````

I see curves linking each letter to itself. So that is “A with A”. Which A with which A, specifically, do you want to link?

Are you meaning to call bezierVertex?

1 Like

Hi, Thanks a lot for your message!
Well, I’d like to link all the “A” letters in the text together and the all the “B” letters and so on… And not each letter to itself. Don’t think I need bezierVertex in this case!?
Best,
L

In your last posted code you are using the matrix stack (with pushMatriix()) to find the coordinates of each letter as you draw it.

If you want to loop over your letters and find the next A, you need all those coordinates saved as absolute coordinates, and you need a sense of “next” – an ordered list; not a HashMap.

There are many ways to do this. One is:

``````class Letter {
float x, y, r;
char c;
Letter(char c, float x, float y, float r) {
this.x = x;
this.y = y;
this.r = r;
this.c = c;
}
}

ArrayList<Letter> letters;
``````

Now make your current draw loop code a preload for your `letters` data which saves a new Letter each time. You can draw at the same time, or you can later loop over `letters` and draw each Letter at the correct place.

Then, to draw bezier curves, loop over `letters` and collect a list of the indices containing the letter you want, for example “a” – you might get back an array of indices (ints) at: [1,5,17, 19, 25 etc]. Then loop over that list starting at 1, and draw a line (or curve) from Letter x,y at idx=n to Letter x,y at idx=n-1. This will draw a line from, for example, letters.get(19) to letters.get(25).

1 Like

Dear Jeremy,
Thank you very much for your precious help!
Actually I think did what you suggest in a sketch (here below) about the same poem but using world coordinates.
I will try to adapt it to my actual sketch…

``````PFont f;
String[] lines;
String message;
String[] sentences;
String title;
String alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ2019,.;:!?\n ";
Letter[]letters;
int x, y;
float letterSize;
float[]originPositionsX = new float [alphabet.length()];
float[]originPositionsY = new float [alphabet.length()];
float stepX= 25;
char upperCaseChar;
boolean drawText = true;
boolean drawLines=false;

void setup() {
size(1080, 1600);
f = createFont("Arial", 5, true);
textFont(f);
lines = loadStrings("Beckett.txt");  //laden des zu analysierenden textes
message = join(lines, " ");
lines= split(message, ",");

letters = new Letter[message.length()];
for (int i =0; i < message.length(); i++) {
letters[i]= new Letter(x*100, 200+y*5, message.charAt(i), random(20, 40));
x +=textWidth(message.charAt(i));
}
}

void draw() {

background(0);
pushMatrix();
pushStyle();
fill(255, 0, 0, 50);
translate(-150, -230);
//rotate(80);
textSize(420);
text("what\nis the\nword", x+50, y);
popStyle();
popMatrix();
translate(20, 40);
smooth();
x=5;
y=0;

for (int i =0; i < message.length(); i++) {
String st=str(message.charAt(i)).toUpperCase();
upperCaseChar= st.charAt(0);
int index = alphabet.indexOf(upperCaseChar);
if (index < 0) continue;

float m = map(mouseX, 50, width-50, 0, 1);
m=constrain(m, 0, 1);
float sortY =index*10+5;
float sortX =stepX;
float interY=lerp(y, sortY, m);
float interX=lerp(x, sortX, m);
letters[i].y=+interY;
letters[i].x=+interX;
x +=textWidth(message.charAt(i));
if (st.equals(",")) {
y+=20;
x=-10;
}
if (drawLines) {
if (originPositionsX[index] !=0 && originPositionsY[index] !=0) {
pushMatrix();
translate(15, 0);
stroke(255, 200, 0, 100);
noFill();
strokeWeight(1);
//line(originPositionsX[index], originPositionsY[index],letters[i].x, letters[i].y);
bezier(originPositionsX[index], originPositionsY[index], letters[i].x, letters[i].y, letters[i].x, letters[i].y+interY/7, letters[i].x, letters[i].y);
popMatrix();
}
originPositionsX[index]= letters[i].x;
originPositionsY[index]= letters[i].y;
}
beginShape();
//line(letters[i].x+5, letters[i].y, letters[i].x+5, letters[i].y+interY/4);
endShape();
}

for (int i=0; i < letters.length; i++) {
println(i);

if (i>951) {
letters[i].x-=15;
letters[i].y+=30;
}

if ( drawText) {
if (message.charAt(i)!=',') {
message.replace(",", "");
letters[i].display();
}
}
if (mousePressed) {
/* letters[i].shake();*/
} else {
letters[i].home();
}
}
}

void keyReleased() {
if (key=='1') drawLines = !drawLines;
if (key=='2') drawText = !drawText;
}

class Letter {

char letter;
float homex, homey;
float x, y;
float sizeText;

Letter(float _x, float _y, char letter_, float sizeText_) {
homex=x=_x;
homey=y=_y;
letter=letter_;
sizeText= sizeText_;
}

void display() {
fill(255);
textAlign(LEFT);
textSize(sizeText);
text(letter, x, y);
}

void shake () {
x+=random(-2, 2);
y+= random(-2, 2);
}

void home() {
x=homex;
y=homey;
}
}
``````
1 Like

Dear Jeremy,
I hardly have time to ‘code’. Here is below where I am now. I managed to create a letter class and to draw them, but I struggle with the lines between the letters, I tried with an alphabet.indexOf(upperCaseChar), but my lines don’t link all the same letters (a with all the a’s, b with all the b’s and so on). Can you tell me what is my mistake please ?!
Thank you very much in advance.
Best wishes,

L

``````import java.util.Map;

PFont font;

String[]lines={
"folly folly for to for to",
"what is the word",
"folly from this all this folly from all this",
"given folly given all this seeing folly seeing all this this",
"what is the word",
"this this this this here all this this here folly given all this",
"seeing folly seeing all this this here for to",
"what is the word",
"see glimpse seem to glimpse need to seem to glimpse folly for to need to seem to glimpse what",
"what is the word",
"and where folly for to need to seem to glimpse what where where what is the word there over there away over there",
"afar afar away over there",
"afaint afaint afar away over there what what",
"what is the word",
"seeing all this all this this all this this here folly for to see what glimpse seem to glimpse need to seem to glimpse",
"afaint afar away over there what",
"folly for to need to seem to glimpse afaint afar away over there what",
"what",
"what is the word",
"what is the word"
};
String alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ2019,.;:!?\n ";
// --------------------------------------------------------

String[] lines2;
String[] c1={};
String[] wordsList2;
int Size;
float r = 40;
float angle = 0;
Letter[]letters;
String message;
char lowerCaseChar;
float interY;
float stepX = 25;
String joinedText;
int ind;
float x, y;
// Note the HashMap's "key" is a String and "value" is an Integer
HashMap<String, Integer> hmYPos = new HashMap<String, Integer>();

//********************************************************************************************************************************************************

void setup() {
size(1400, 1400);
font = createFont("helvetica", 20);
textFont(font);
textAlign(CENTER);
message = join(lines, ",");
lines = split(message, ",");
//println(message.length());
letters = new Letter[message.length()];
for (int i =0; i<message.length(); i++) {
letters[i]= new Letter(x, y, message.charAt(i), r);
}
prepare();
}

//********************************************************************************************************************************************************

void draw() {
background(0);
translate (width/2, height/2);
smooth();
scale(0.7);
float posX = 0;
float arcLength=0;
float posY = 0;

float[]originPositionsX = new float [alphabet.length()];
float[]originPositionsY = new float [alphabet.length()];

for (int j = 0; j < lines.length; j++) {

if ( j<=lines.length) {
r=45*(j+1);
}

String[]wordsInThatLine = split(lines[j], " ");
for (int j2 = 0; j2 < wordsInThatLine.length; j2++) {
int index = hmYPos.get(wordsInThatLine[j2]);

if (index<0) continue;
arcLength+=15;
mouseX=constrain(mouseX, width/2, width);
float sortY = 0;
r= map(mouseX, width/2, width, 75+45*j+1, 150+hmYPos.get(wordsInThatLine [j2]));
sortY=r;
float m=map(mouseX, width/2, width, 0, 1);
m = constrain(m, 0, 1);
interY = lerp(posY, sortY, m);

for (int j3 = 0; j3 < wordsInThatLine[j2].length(); j3++) {
char currentChar= wordsInThatLine[j2].charAt(j3);
letters[j3]= new Letter(posX, posY, currentChar, r);
float w=textWidth(currentChar);
arcLength+=w+5;
float theta =PI+arcLength/r;

pushMatrix();
translate(r*cos(theta), r*sin(theta));
scale(0.7);
rotate(theta+PI/2);
String joinedText = join(wordsInThatLine, " ");
String st=str(joinedText.charAt(j3)).toUpperCase();
char upperCaseChar= st.charAt(0);
ind = alphabet.indexOf(upperCaseChar);
if (ind < 0) continue;
noFill();
stroke(181, 157, 0, 250);
strokeWeight(1);
line(originPositionsX[ind], originPositionsY[ind], posX, interY);

noFill();
strokeWeight(hmYPos.get(wordsInThatLine[j2])*0.01+0.1);
stroke(0, 50, 220, 100);
//ellipse(0, -10, hmYPos.get(wordsInThatLine[j2])*0.07+15, hmYPos.get(wordsInThatLine[j2])*0.07+15);
fill(255, 200);
textAlign(CENTER, BASELINE);
float SText = hmYPos.get(wordsInThatLine[j2])*0.035;
textSize(SText+20);
letters[j3].display();
//text(currentChar, 0, 0);
popMatrix();

arcLength+=w/2;
}
}
}
originPositionsX[ind]= posX;
originPositionsY[ind]= interY;
}

//------------------------------------------------------------

void prepare() {
HashMap<String, Integer> hm1 = new HashMap<String, Integer>();
String message;

message= join(lines, " "); // Join all the separated strings
lines2=split(message, ",");// Split them into sentences according to the comas
// Now we have a copy of the whole text

// Init
wordsList2 = split(join(lines, " "), " "); // We do the same than above for a new copy to initialize the HashMap
for (String s : wordsList2) {              // We loop across the whole list of strings
hm1.put(s.toLowerCase(), 0);             // We fill the HashMap (hm1) and put the strings to lowerCase and put all at 0
textSize(abs(hm1.get(s)*5+Size)+15);     // We pass a textSize
}

// Counting
for (int i=0; i<lines2.length; i++) {           // We loop across the whole strings
String word = lines2[i].toLowerCase().trim(); // We put the strings to lowerCase and get rid of comas, points, etc.
if (hm1.get(word) != null) {                  // If the HashMap is not null
hm1.put(word, ((int) (hm1.get(word)))+1);   // We fill the HashMap with the 2nd list of strings (word) and we add 1
}
}

//// Using an enhanced loop to iterate over each entry
for (Map.Entry me : hm1.entrySet()) {
c1 = (String[]) append (c1, me.getKey());
}//for
c1=sort(c1); //We sort the strings according to the alphabet
//println(c1);

// simulate output and save the line number for each word in sorted position
int posY=0;
for (String s : c1) {
hmYPos.put( s, posY);
//Size=hmYPos.get(s);
posY += 25;
}
}
//---------------------------------------------------------------------------------

class Letter {

char letter;
float x, y, r;

Letter(float _x, float _y, char _letter, float _r) {
x=_x;
y=_y;
r=_r;
letter=_letter;
}
void display() {
fill(255);
noStroke();
text(letter, x, y);
}
}//
//
``````
1 Like

Currently you are using this to place each letter.

``````        pushMatrix();
translate(r*cos(theta), r*sin(theta));
scale(0.7);
rotate(theta+PI/2);
``````

You can’t rotate and translate like this if you want to know each letter’s position coordinates. You have to calculate the x, y position of each letter on the canvas and then store it. Then you will have coordinates to draw connecting lines between those coordinates.

1 Like

Thank you very much for your answer @jeremydouglass!
Not sure I get it, you mean that I first need to calculate the x,y position of each letter then I can connect lines between these coordinates and after I can use

``````pushMatrix();
translate(r*cos(theta), r*sin(theta));
scale(0.7);
rotate(theta+PI/2);
``````

in order to pass polar coordinates to letters and lines?!