diff --git a/TP5/README.md b/TP5/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..868ad3e68094b8432d4ed9d6115c2694b27f5f7e
--- /dev/null
+++ b/TP5/README.md
@@ -0,0 +1,18 @@
+# Visualisation processing
+
+## TP1
+**Enoncé du tp : http://malacria.com/teachings/RVA/visualisation/tpvisu1.html**
+
+
+## TP2
+**Enoncé du tp : http://malacria.com/teachings/RVA/visualisation/tpvisu2.html**
+
+### Définir les marques
+
+Nous choisisons les attributs "population" et "altitude" pour encoder visuellement les villes. Voici comment nous pourrions associer une variable rétinienne à chaque attribut :
+
+- Population : la variable rétinienne associée à la population sera la taille du marqueur. Ainsi, une ville avec une population plus élevée aurait une marque plus grande qu'une ville avec une population plus faible.
+
+- Altitude : la variable rétinienne associée à l'altitude sera la couleur du marqueur. Par exemple, les villes ayant une altitude plus élevée seront représentées par des marqueurs jaunes à rouge, tandis que les villes ayant une altitude plus basse seront représentées par des marqueurs bleus.
+
+On met en place aussi un histogramme des valeurs de population, c'est-à-dire le nombre de valeurs appartenant à chaque intervalle de l'axe afin d'améliorer la visualisation des données.
diff --git a/TP5/sketch_240321a/City.pde b/TP5/sketch_240321a/City.pde
new file mode 100644
index 0000000000000000000000000000000000000000..eaa47676d6259ee12b8acd7981fafde2f0752ed7
--- /dev/null
+++ b/TP5/sketch_240321a/City.pde
@@ -0,0 +1,36 @@
+class City { 
+      int postalcode; 
+      String name; 
+      float x; 
+      float y; 
+      float population; 
+      float density; 
+      float altitude;
+
+      // put a drawing function in here and call from main drawing loop }
+      public City(String postalcode, String name, float x, float y, float population, float surface, float altitude) { 
+      this.postalcode = Integer.parseInt(postalcode);
+      this.name = name; 
+      this.x = x; 
+      this.y = y; 
+      this.population = population; 
+      this.density = population/surface ;
+      this.altitude = altitude;
+    }
+    
+    void draw() {
+    //map the altitude to the color in porcentage
+    float porcentageAlt = map(this.altitude, minAltitude, maxAltitude, 0, 100);
+    float hue = getColorForAltitude(porcentageAlt);
+    
+    // Set marker size based on population
+    float size = map(this.population, minPopulation, maxPopulation, 3, 100);
+
+    // Draw marker
+    fill(hue, 100, 100);
+    ellipse(x, y, size, size);
+}
+
+
+}
+    
diff --git a/TP5/sketch_240321a/ColorPalette.pde b/TP5/sketch_240321a/ColorPalette.pde
new file mode 100644
index 0000000000000000000000000000000000000000..0db55417eb72e87a99d1b65165a01eaa12cff413
--- /dev/null
+++ b/TP5/sketch_240321a/ColorPalette.pde
@@ -0,0 +1,3 @@
+float getColorForAltitude(float altitude) {
+    return map(altitude, 0, 100, 230, -50);
+}
diff --git a/TP5/sketch_240321a/Legends.pde b/TP5/sketch_240321a/Legends.pde
new file mode 100644
index 0000000000000000000000000000000000000000..8c4b5fe07d8c2cd02ddebe14df41732e94431088
--- /dev/null
+++ b/TP5/sketch_240321a/Legends.pde
@@ -0,0 +1,78 @@
+/**
+* Creates legend for altitude values using a color gradient
+*/
+void drawAltitudeLegend(float minVal, float maxVal, float x, float y, float w, float h) {
+  int barCount = 50;
+  float barWidth = w / barCount;
+  float highestBarHeight = h * 0.9;
+  
+  // Draw title
+  fill(0);
+  textAlign(CENTER, CENTER);
+  text("Altitude distribution", x + w / 2, y - 10);
+  
+  // Draw axis
+  stroke(0);
+  line(x, y + h, x + w, y + h); // x axis
+  
+  // Draw labels
+  fill(0);
+  textAlign(CENTER, CENTER);
+  text(minVal, x, y + h + 10);
+  text(maxVal, x + w, y + h + 10);
+ 
+  // Draw bars
+  for (int i = 0; i < barCount; i++) {
+    float porcentageAlt = map(i, 0, barCount, 0, 100);
+    float hue = getColorForAltitude(porcentageAlt);
+    fill(hue, 100, 100);
+    noStroke();
+    rect(x + i * barWidth, y, barWidth, highestBarHeight);
+  }
+}
+
+void drawDistributionPopulationLegend(int minPopulation, int maxPopulation, float x, float y, float width, float height, int numberOfDiv, float[] populationValues) {
+  // Calcul de l'histogramme
+  int[] histogram = new int[numberOfDiv];
+  for (int i = 0; i < populationValues.length; i++) {
+    int val = (int) map(populationValues[i], minPopulation, maxPopulation, 0, numberOfDiv);
+    if (val >= 0 && val < numberOfDiv) {
+      histogram[val]++;
+    }
+  }
+  
+  // Recherche du maximum de l'histogramme
+  int maxHistogram = 0;
+  for (int i = 0; i < histogram.length; i++) {
+    if (histogram[i] > maxHistogram) {
+      maxHistogram = histogram[i];
+    }
+  }
+  
+  // Dessin de l'axe et des barres de l'histogramme
+  float binWidth = width / numberOfDiv;
+
+  fill(220, 100, 100);
+  
+  for (int i = 0; i < numberOfDiv; i++) {
+    float currentX = x + i * binWidth;
+    float barHeight = map(histogram[i], 0, maxHistogram, 0, height);
+    rect(currentX, y - barHeight, binWidth, barHeight);
+  }
+  
+  // Dessin de la légende
+
+  // Draw title
+  fill(0);
+  textAlign(CENTER, CENTER);
+  text("Distribution de la Population", x + width / 2, y + height + 10);
+  text(minPopulation, x, y + 10);
+  text(maxPopulation, x + width, y + 10);
+
+  for (int i = 0; i <= numberOfDiv; i++) {
+    float value = map(i, 0, numberOfDiv, minPopulation, maxPopulation); // Valeur du label
+    String label = nf(value, 0, 0); // Formatage du label
+    float xPos = map(i, 0, numberOfDiv, 0, width); // Position x du label
+    line(x + xPos , y , x + xPos, y + 4);
+  }
+}
diff --git a/TP5/sketch_240321a/sketch_240321a.pde b/TP5/sketch_240321a/sketch_240321a.pde
index e7a0a80b920e7d6f9325b18567a5c25a292812ec..9918691014d9d948702e84a22b4108b434cb85e6 100644
--- a/TP5/sketch_240321a/sketch_240321a.pde
+++ b/TP5/sketch_240321a/sketch_240321a.pde
@@ -10,27 +10,34 @@ int minAltitude, maxAltitude;
 int x = 1;
 int y = 2;
 
-// and the tables in which the city coordinates will be stored
-float xList[];
-float yList[];
+City cities[];
+
+int legendsHeight=100;
 
 void setup() {
-  size(800,800);
+  size(900,900);
   readData();
 }
 
 void draw(){
   background(255);
-  color black = color(0);
-  for (int i = 0 ; i < totalCount ; ++i) {
+  for (int i = 0 ; i < totalCount - 2 ; ++i) {
     // draw a point at the coordinates of the city
-    float x = mapX(xList[i]);
-    float y = mapY(yList[i]);
-    stroke(black);
-    point(x, y);
+    cities[i].draw();
   }
 
   updatePixels();
+  
+  // Draw the distribution of the altitude values
+  float[] altitudeValues = new float[cities.length];
+  for (int i = 0; i < cities.length - 2; i++) {
+    altitudeValues[i] = cities[i].altitude;
+  }
+
+  if (legendsHeight > 0) {
+    drawLegend();
+  }
+
 
 }
 
@@ -47,14 +54,15 @@ void readData() {
   
   parseInfo(lines[0]); // read the header line
   
-  xList = new float[totalCount];
-  yList = new float[totalCount];
+  cities = new City[totalCount];
 
   for (int i = 2 ; i < totalCount ; ++i) {
     String[] columns = split(lines[i], TAB);
-    xList[i-2] = float (columns[x]);
-    yList[i-2] = float (columns[y]);
+      float pointX = float (columns[x]);
+      float pointY = float (columns[y]);
+      cities[i-2] = new City(columns[0], columns[4], mapX(pointX), mapY(pointY), float (columns[5]), float (columns[6]), float (columns[7]));
   }
+  println("City list created: " + cities.length + " cities");
 
 }
 
@@ -81,3 +89,20 @@ float mapX(float x) {
 float mapY(float y) {
   return map(y, maxY, minY, 0, 800);
 }
+
+void drawLegend() {
+  float distributionX = 50;
+  float distributionY = height - legendsHeight;
+  float distributionWidth = width - 100;
+  float distributionHeight = 50;
+  drawAltitudeLegend(minAltitude, maxAltitude, distributionX, distributionY, distributionWidth, distributionHeight);
+  // get list of population values from the cities
+  float[] populationValues = new float[cities.length];
+  for (int i = 0; i < cities.length - 2; i++) {
+    populationValues[i] = cities[i].population;
+  }
+
+  int numberOfDiv = 30;
+  // draw the population distribution
+  drawDistributionPopulationLegend(minPopulation, maxPopulation, distributionX, distributionY, distributionWidth, distributionHeight, numberOfDiv, populationValues);
+}