Skip to content

Commit 5a8f268

Browse files
author
Agathe Lenclen
committed
Add a DataPoint, and DataPoint collection to keep track of the data in the algorithm
1 parent 3a1118b commit 5a8f268

File tree

4 files changed

+180
-94
lines changed

4 files changed

+180
-94
lines changed

examples/UsingSquarify/UsingSquarify.pde

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ float CANVAS_ORIGIN_X = 0; // The x origin of the canvas to fill
99
float CANVAS_ORIGIN_Y = 0; // The y origin of the canvas to fill
1010

1111
// SQUARIFY DATA
12-
ArrayList<SquarifiedRect> rects; // The rects list will contain geometry for each rectangle to draw
12+
ArrayList<SquarifyRect> rects; // The rects list will contain geometry for each rectangle to draw
1313
ArrayList<Float> values = new ArrayList<Float>(Arrays.asList(50f, 25f, 100f, 10f, 75f)); // Values defining the squarified layout
1414

1515
void setup() {
@@ -25,13 +25,14 @@ void draw() {
2525

2626
for (int i = 0; i < rects.size(); i++) {
2727
// Draw a rectangle
28-
SquarifiedRect r = rects.get(i);
28+
SquarifyRect r = rects.get(i);
2929
fill(map(r.getValue(), 0, 100, 50, 255));
3030
rect(r.getX(), r.getY(), r.getDx(), r.getDy());
3131

3232
// Draw rectangle value
33+
textAlign(CENTER, CENTER);
3334
textSize(14);
3435
fill(0);
35-
text(round(r.getValue()), r.getX() + r.getDx()/2, r.getY() + r.getDy()/2);
36+
text("Id: " + r.getId() + ", Value: " + round(r.getValue()), r.getX() + r.getDx()/2, r.getY() + r.getDy()/2);
3637
}
3738
}

src/squarify/library/Squarify.java

Lines changed: 38 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package squarify.library;
22

33
import java.util.ArrayList;
4-
import java.util.Collections;
54
import java.util.List;
65

6+
import squarify.library.SquarifyData.DataPoint;
7+
78
/**
89
* A class to generate a squarified treemap layout from a set of values.
910
*
@@ -13,82 +14,31 @@
1314

1415
public class Squarify {
1516

16-
private ArrayList<SquarifiedRect> rects;
17-
private ArrayList<Float> sizes;
18-
private float width, height;
17+
private ArrayList<SquarifyRect> rects;
18+
private SquarifyData data;
1919

2020
public Squarify(ArrayList<Float> sizes, float x, float y, float width, float height) {
21-
this.width = width;
22-
this.height = height;
23-
this.sizes = this.sortDescending(sizes);
24-
25-
List<Float> values = this.normalizeSizes(this.sizes, width, height);
26-
rects = squarify(values, x, y, width, height);
21+
data = new SquarifyData(sizes, width, height);
22+
rects = squarify(data.getDataPoints(), x, y, width, height);
2723
}
2824

2925
/**
3026
* Getter for the list of rectangle's geometry
3127
* @return rects
3228
*/
33-
public ArrayList<SquarifiedRect> getRects() {
29+
public ArrayList<SquarifyRect> getRects() {
3430
return this.rects;
3531
}
36-
37-
/**
38-
* Helper that sorts a list in descending order
39-
* @param s A list of values
40-
* @return The list of values ordered descending
41-
*/
42-
private ArrayList<Float> sortDescending(ArrayList<Float> s) {
43-
Collections.sort(s);
44-
Collections.reverse(s);
45-
return s;
46-
}
47-
48-
/**
49-
* Helper that normalizes the sizes to the proportion of the canvas.
50-
*
51-
* @param sizes A list of values to squarify
52-
* @param width The canvas width
53-
* @param height The canvas height
54-
* @return
55-
*/
56-
private ArrayList<Float> normalizeSizes(ArrayList<Float> sizes, float width, float height) {
57-
float totalSize = sum(sizes);
58-
float totalArea = width * height;
59-
ArrayList<Float> normalized = new ArrayList<Float>(sizes.size());
6032

61-
for (int i = 0; i < sizes.size(); i++) {
62-
normalized.add(sizes.get(i) * totalArea / totalSize);
63-
}
64-
return normalized;
65-
}
66-
67-
/**
68-
* Helper that denormalized a normalized size to its original value
69-
* This helper is only needed if you want to print the size in the rectangles on your canvas.
70-
*
71-
* @param sizes The list of sizes to squarify
72-
* @param normalizedValue The normalized size to reverse
73-
* @param width The canvas width
74-
* @param height The canvas height
75-
* @return
76-
*/
77-
private Float denormalizeSize(ArrayList<Float> sizes, float normalizedValue, float width, float height) {
78-
float totalSize = sum(sizes);
79-
float totalArea = width * height;
80-
return (float) normalizedValue * totalSize / totalArea;
81-
}
82-
8333
/**
84-
* Helper that sums all the values of float list
85-
* @param values A list of float values
34+
* Helper that sums all the values of DataPoint
35+
* @param values A list of DataPoint values
8636
* @return The sum of these values
8737
*/
88-
private float sum(List<Float> values) {
38+
private float sumNormalizedValues(List<DataPoint> l) {
8939
float result = 0;
90-
for (int i = 0; i < values.size(); i++) {
91-
result += values.get(i);
40+
for (int i = 0; i < l.size(); i++) {
41+
result += l.get(i).getNormalizedValue();
9242
}
9343
return result;
9444
}
@@ -105,13 +55,13 @@ private float sum(List<Float> values) {
10555
* @param dy
10656
* @return
10757
*/
108-
private ArrayList<SquarifiedRect> layoutRow(List<Float> values, float x, float y, float dx, float dy) {
109-
float coveredArea = sum(values);
58+
private ArrayList<SquarifyRect> layoutRow(List<DataPoint> values, float x, float y, float dx, float dy) {
59+
float coveredArea = sumNormalizedValues(values);
11060
float width = coveredArea / dy;
111-
ArrayList<SquarifiedRect> rects = new ArrayList<SquarifiedRect>();
61+
ArrayList<SquarifyRect> rects = new ArrayList<SquarifyRect>();
11262
for (int i = 0; i < values.size(); i++) {
113-
rects.add(new SquarifiedRect(x, y, width, values.get(i) / width, denormalizeSize(this.sizes, values.get(i), this.width, this.height)));
114-
y += values.get(i) / width;
63+
rects.add(new SquarifyRect(x, y, width, values.get(i).getNormalizedValue() / width, values.get(i).getId(), values.get(i).getValue()));
64+
y += values.get(i).getNormalizedValue() / width;
11565
}
11666
return rects;
11767
}
@@ -128,13 +78,13 @@ private ArrayList<SquarifiedRect> layoutRow(List<Float> values, float x, float y
12878
* @param dy
12979
* @return
13080
*/
131-
private ArrayList<SquarifiedRect> layoutCol(List<Float> values, float x, float y, float dx, float dy) {
132-
float coveredArea = sum(values);
81+
private ArrayList<SquarifyRect> layoutCol(List<DataPoint> values, float x, float y, float dx, float dy) {
82+
float coveredArea = sumNormalizedValues(values);
13383
float height = coveredArea / dx;
134-
ArrayList<SquarifiedRect> rects = new ArrayList<SquarifiedRect>();
84+
ArrayList<SquarifyRect> rects = new ArrayList<SquarifyRect>();
13585
for (int i = 0; i < values.size(); i++) {
136-
rects.add(new SquarifiedRect(x, y, values.get(i) / height, height, denormalizeSize(this.sizes, values.get(i), this.width, this.height)));
137-
x += values.get(i) / height;
86+
rects.add(new SquarifyRect(x, y, values.get(i).getNormalizedValue() / height, height, values.get(i).getId(), values.get(i).getValue()));
87+
x += values.get(i).getNormalizedValue() / height;
13888
}
13989
return rects;
14090
}
@@ -148,14 +98,14 @@ private ArrayList<SquarifiedRect> layoutCol(List<Float> values, float x, float y
14898
* @param dy
14999
* @return
150100
*/
151-
private SquarifiedRect leftoverRow(List<Float> values, float x, float y, float dx, float dy) {
152-
float coveredArea = sum(values);
101+
private SquarifyRect leftoverRow(List<DataPoint> values, float x, float y, float dx, float dy) {
102+
float coveredArea = sumNormalizedValues(values);
153103
float width = coveredArea / dy;
154104
float leftoverX = x + width;
155105
float leftoverY = y;
156106
float leftoverDx = dx - width;
157107
float leftoverDy = dy;
158-
return new SquarifiedRect(leftoverX, leftoverY, leftoverDx, leftoverDy);
108+
return new SquarifyRect(leftoverX, leftoverY, leftoverDx, leftoverDy);
159109
}
160110

161111
/**
@@ -167,14 +117,14 @@ private SquarifiedRect leftoverRow(List<Float> values, float x, float y, float d
167117
* @param dy
168118
* @return
169119
*/
170-
private SquarifiedRect leftoverCol(List<Float> values, float x, float y, float dx, float dy) {
171-
float coveredArea = sum(values);
120+
private SquarifyRect leftoverCol(List<DataPoint> values, float x, float y, float dx, float dy) {
121+
float coveredArea = sumNormalizedValues(values);
172122
float height = coveredArea / dx;
173123
float leftoverX = x;
174124
float leftoverY = y + height;
175125
float leftoverDx = dx;
176126
float leftoverDy = dy - height;
177-
return new SquarifiedRect(leftoverX, leftoverY, leftoverDx, leftoverDy);
127+
return new SquarifyRect(leftoverX, leftoverY, leftoverDx, leftoverDy);
178128
}
179129

180130
/**
@@ -186,7 +136,7 @@ private SquarifiedRect leftoverCol(List<Float> values, float x, float y, float d
186136
* @param dy
187137
* @return
188138
*/
189-
private SquarifiedRect leftover(List<Float> values, float x, float y, float dx, float dy) {
139+
private SquarifyRect leftover(List<DataPoint> values, float x, float y, float dx, float dy) {
190140
if (dx >= dy) {
191141
return leftoverRow(values, x, y, dx, dy);
192142
}
@@ -202,7 +152,7 @@ private SquarifiedRect leftover(List<Float> values, float x, float y, float dx,
202152
* @param dy
203153
* @return
204154
*/
205-
private ArrayList<SquarifiedRect> layout(List<Float> values, float x, float y, float dx, float dy) {
155+
private ArrayList<SquarifyRect> layout(List<DataPoint> values, float x, float y, float dx, float dy) {
206156
if (dx >= dy) {
207157
return layoutRow(values, x, y, dx, dy);
208158
}
@@ -219,8 +169,8 @@ private ArrayList<SquarifiedRect> layout(List<Float> values, float x, float y, f
219169
* @param dy
220170
* @return
221171
*/
222-
private float worstRatio(List<Float> values, float x, float y, float dx, float dy) {
223-
ArrayList<SquarifiedRect> rects = layout(values, x, y, dx, dy);
172+
private float worstRatio(List<DataPoint> values, float x, float y, float dx, float dy) {
173+
ArrayList<SquarifyRect> rects = layout(values, x, y, dx, dy);
224174
float max = 0;
225175
for (int i = 0; i < rects.size(); i++) {
226176
float rectDx = rects.get(i).getDx();
@@ -242,15 +192,15 @@ private float worstRatio(List<Float> values, float x, float y, float dx, float d
242192
* @param dy Current height of leftover canvas
243193
* @return
244194
*/
245-
private ArrayList<SquarifiedRect> squarify(List<Float> values, float x, float y, float dx, float dy) {
246-
ArrayList<SquarifiedRect> rects = new ArrayList<SquarifiedRect>();
195+
private ArrayList<SquarifyRect> squarify(List<DataPoint> values, float x, float y, float dx, float dy) {
196+
ArrayList<SquarifyRect> rects = new ArrayList<SquarifyRect>();
247197

248198
if (values.size() == 0) {
249199
return rects;
250200
}
251201

252202
if (values.size() == 1) {
253-
rects.add(new SquarifiedRect(x, y, dx, dy, denormalizeSize(this.sizes, values.get(0), this.width, this.height)));
203+
rects.add(new SquarifyRect(x, y, dx, dy, values.get(0).getId(), values.get(0).getValue()));
254204
return rects;
255205
}
256206

@@ -259,10 +209,10 @@ private ArrayList<SquarifiedRect> squarify(List<Float> values, float x, float y,
259209
i += 1;
260210
}
261211

262-
List<Float> current = values.subList(0, i);
263-
List<Float> remaining = values.subList(i, values.size());
212+
List<DataPoint> current = values.subList(0, i);
213+
List<DataPoint> remaining = values.subList(i, values.size());
264214

265-
SquarifiedRect currentLeftover = leftover(current, x, y, dx, dy);
215+
SquarifyRect currentLeftover = leftover(current, x, y, dx, dy);
266216
rects.addAll(layout(current, x, y, dx, dy));
267217
rects.addAll(squarify(remaining, currentLeftover.getX(), currentLeftover.getY(), currentLeftover.getDx(), currentLeftover.getDy()));
268218
return rects;
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package squarify.library;
2+
3+
import java.util.ArrayList;
4+
import java.util.Collections;
5+
import java.util.Comparator;
6+
import java.util.List;
7+
8+
9+
public class SquarifyData {
10+
private ArrayList<DataPoint> data; // List of data points holding value, normalized value and id
11+
private static float totalSize; // Total size of values
12+
private static float totalArea; // Total area of canvas
13+
private static int length; // Total amount of values
14+
15+
public SquarifyData(ArrayList<Float> values, float width, float height) {
16+
// Process data
17+
this.data = new ArrayList<DataPoint>();
18+
setValues(values);
19+
sortDescending();
20+
21+
// Compute values
22+
totalSize = sumValues(this.data);
23+
length = values.size();
24+
totalArea = width * height;
25+
26+
// Normalize data to canvas area
27+
normalize();
28+
}
29+
30+
/**
31+
* Helper that sorts a list in descending order
32+
* @param s A list of values
33+
* @return The list of values ordered descending
34+
*/
35+
private void sortDescending() {
36+
Collections.sort(this.data, new Comparator<DataPoint>() {
37+
@Override
38+
public int compare(DataPoint a1, DataPoint a2) {
39+
return Float.compare(a1.getValue(), a2.getValue());
40+
}
41+
});
42+
Collections.reverse(this.data);
43+
}
44+
45+
/**
46+
* Create one DataPoint per size value
47+
* @param values
48+
*/
49+
private void setValues(ArrayList<Float> values) {
50+
for (int i = 0; i < values.size(); i++) {
51+
data.add(new DataPoint(i, values.get(i)));
52+
}
53+
}
54+
55+
/**
56+
* Normalize data to canvas area
57+
*/
58+
private void normalize() {
59+
for (int i = 0; i < this.data.size(); i++) {
60+
this.data.get(i).normalize();
61+
}
62+
}
63+
64+
/**
65+
* Helper that sums all the values of DataPoint
66+
* @param values A list of DataPoint values
67+
* @return The sum of these values
68+
*/
69+
private float sumValues(List<DataPoint> l) {
70+
float result = 0;
71+
for (int i = 0; i < l.size(); i++) {
72+
result += l.get(i).getValue();
73+
}
74+
return result;
75+
}
76+
77+
public float getTotalSize() {
78+
return totalSize;
79+
}
80+
81+
public int getLength() {
82+
return length;
83+
}
84+
85+
public ArrayList<DataPoint> getDataPoints() {
86+
return this.data;
87+
}
88+
89+
public DataPoint getDataPoint(int i) {
90+
return this.data.get(i);
91+
}
92+
93+
/**
94+
* DataPoint holds the original size value passed as parameter to Squarify
95+
* It also stores the id of the value, to keep track of it as the squarify
96+
* algorithm requires to sort values descending.
97+
* @author agathelenclen
98+
*
99+
*/
100+
public class DataPoint {
101+
private float value;
102+
private float normalizedValue;
103+
private int id;
104+
105+
public DataPoint(int id, float value) {
106+
this.id = id;
107+
this.value = value;
108+
}
109+
110+
/**
111+
* Normalizes the value size to the proportion of the canvas.
112+
*/
113+
private void normalize() {
114+
this.normalizedValue = this.value * totalArea / totalSize;
115+
}
116+
117+
public float getValue() {
118+
return value;
119+
}
120+
121+
public float getNormalizedValue() {
122+
return normalizedValue;
123+
}
124+
125+
public int getId() {
126+
return id;
127+
}
128+
}
129+
}

0 commit comments

Comments
 (0)