diff --git a/src/style.css b/src/style.css
index 2b1b6e378fa59d1100032672b878c6682cdd2720..e4cd5e9f01d504b29f3fdab20e96cccd1725b858 100644
--- a/src/style.css
+++ b/src/style.css
@@ -1,11 +1,12 @@
 body {
     margin: 0;
+    background-color: aliceblue;
     width: 100%;
     height: 100%;
 }
 .main_view {
     float: left;
-    background-color: aliceblue;
+
     width: 100%;
     margin: 0;
 }
@@ -14,7 +15,7 @@ svg {
     background-color: white;
     border: 2px solid black;
     border-radius: 5px;
-    margin: 1%;
+    margin: 2% 2% 0 2%;
 }
 
 .filters-container{
diff --git a/src/visualizacion.html b/src/visualizacion.html
index df4a10985ccc89bf8160b98a37fd522c98d94ea9..42cd73a0d255fa78415f8bcf42d942559427e904 100644
--- a/src/visualizacion.html
+++ b/src/visualizacion.html
@@ -15,7 +15,7 @@
         </div>
         <div class="filters-container">
             <label for="color_scheme">
-                <h3>Coloreado por:</h3>
+                <h2>Coloreado por:</h2>
             </label>
             <select id="color_scheme" onchange="changeSelection(event)">
                 <option value="platform">Plataforma</option>
@@ -23,13 +23,13 @@
             </select>
             <br>
             <label>
-                <h3>Búsqueda:</h3>
+                <h2>Búsqueda:</h2>
                 <input type="search" id="search">
             </label>
 
         </div>
         <div class="filters-container">
-            <h3>Filtros</h3>
+            <h2>Filtros</h2>
             <div id="filters">
                 <!-- Aquí se generarán los checkboxes dinámicamente -->
             </div>
diff --git a/src/visualizacion.js b/src/visualizacion.js
index f6c74a3be06cb639e8a59784aae7350df7b0436f..c27e1de30c4518d49c38e2414dfebab1f31a2faf 100644
--- a/src/visualizacion.js
+++ b/src/visualizacion.js
@@ -67,18 +67,20 @@ let min_y = 0;
 let max_x = 10;
 let max_y = 10;
 
-const width = 800;
+const width = 950;
 const height = 400;
 const margin_x = 62;
 const margin_y = 60;
-const right_margin = 300;
+const right_margin = 400;
 const rectAparitionTime = 150;
 const radiusTransition = 300;
-const maxBubbleCount = 50;
+const maxBubbleCount = 100;
 
 
-const svg = d3.select('.main_view').insert('svg', '.filters-container')
-    .attr("width", width + 2 * margin_x).attr("height", height + 2 * margin_y);
+const svg = d3.select('.main_view')
+    .insert('svg', '.filters-container')
+    .attr("width", width + 2 * margin_x)
+    .attr("height", height + 2 * margin_y)
 
 svg.append('defs').append('clipPath')
     .attr("id", "content-clip")
@@ -168,6 +170,15 @@ function createAxis() {
         .attr('y', 0);
 
     scatter = contentGroup.append('g');
+
+    svg.append("text")
+        .attr("x", width - right_margin + 1.3*margin_x)
+        .attr("y", 3.7*margin_y)
+        .attr("class", "legend-title")
+        .style("font-size", "26px")
+        .style("font-weight", "bold")
+        .style("font-family", "Georgia, serif")
+        .text("Leyenda");
 }
 
 d3.csv('files/games-data.csv').then((data) => {
@@ -181,13 +192,12 @@ d3.csv('files/games-data.csv').then((data) => {
         elem.critics = +elem.critics;
         elem.users = +elem.users;
         elem.genre = [...new Set(elem.genre.split(','))];
-        elem.id = elem.name.replaceAll(/[ :'"()\[\]]*/g, '') + "-" + elem.platform;
     });
 
 
     xScale = d3.scaleLinear().domain([min_x, max_x]).range([0, width-right_margin]);
     yScale = d3.scaleLinear().domain([min_y, max_y]).range([height, 0]);
-    radiusScale = d3.scaleSqrt().domain([0, d3.max(data, elem => elem["critics"]) || 1]).range([5, 15]);
+    radiusScale = d3.scaleSqrt().domain([0, d3.max(data, elem => elem["critics"]) || 10]).range([7, 15]);
 
     elegibleData = data.sort((a, b) => {
         return (b["critics"] + b["users"]) - (a["critics"] + a["users"])
@@ -206,7 +216,7 @@ function handleMouseOver(event, d) {
         .transition()
         .duration(radiusTransition)
         .ease(d3.easeQuadInOut)
-        .attr("r", radiusScale(d.critics) * 1.4)
+        .attr("r", radiusScale(d.critics) * 1.5)
 
     // Calcula las posiciones del círculo transformadas
     const cx = transform.applyX(xScale(d["user score"]));
@@ -220,19 +230,21 @@ function handleMouseOver(event, d) {
     const rects = svg.append("g").attr("class", "rects");
     const texts = svg.append("g").attr("class", "texts");
 
+    const textLocation = width - right_margin + 1.4*margin_x;
+
     // Añade el texto al tooltip
     const text = texts.append("text")
-        .attr("x", cx + visualOffsetX + 10) // Posiciona el texto con offset
-        .attr("y", cy + visualOffsetY + 20)
-        .style("font-size", "15px")
+        .attr("x", width + margin_x) // Posiciona el texto con offset
+        .attr("y", margin_y)
+        .style("font-size", "14px")
         .style("font-family", "Georgia, serif")
         .style("fill", "black")
 
     text.append("tspan")
         .text(`${d.name}`)
-        .style("font-size", "18px")
+        .style("font-size", "20px")
         .style("font-weight", "bold")
-        .attr("x", cx + visualOffsetX + 10)
+        .attr("x", textLocation)
         .attr("dy", "1.2em")
         .style("opacity", 0)
         .transition()
@@ -242,7 +254,7 @@ function handleMouseOver(event, d) {
 
     text.append("tspan")
         .text(`Géneros: ${d.genre.join(", ")}`)
-        .attr("x", cx + visualOffsetX + 10)
+        .attr("x", textLocation)
         .attr("dy", "1.2em")
         .style("opacity", 0)
         .transition()
@@ -252,7 +264,7 @@ function handleMouseOver(event, d) {
 
     text.append("tspan")
         .text(`Fecha: ${d["r-date"]}`)
-        .attr("x", cx + visualOffsetX + 10)
+        .attr("x", textLocation)
         .attr("dy", "1.2em")
         .style("opacity", 0)
         .transition()
@@ -262,7 +274,7 @@ function handleMouseOver(event, d) {
 
     text.append("tspan")
         .text(`Desarrolladores: ${d.developer}`)
-        .attr("x", cx + visualOffsetX + 10)
+        .attr("x", textLocation)
         .attr("dy", "1.2em")
         .style("opacity", 0)
         .transition()
@@ -272,23 +284,26 @@ function handleMouseOver(event, d) {
 
     text.append("tspan")
         .text(`Consola: ${d.platform}`)
-        .attr("x", cx + visualOffsetX + 10)
+        .attr("x", textLocation)
         .attr("dy", "1.2em")
         .style("opacity", 0)
         .transition()
         .duration(rectAparitionTime)
         .ease(d3.easeQuadOut)
         .style("opacity", 1)
+    if(d.players !== "No info"){
+        text.append("tspan")
+            .text(`Jugadores: ${d.players}`)
+            .attr("x", textLocation)
+            .attr("dy", "1.2em")
+            .style("opacity", 0)
+            .transition()
+            .duration(rectAparitionTime)
+            .ease(d3.easeQuadOut)
+            .style("opacity", 1)
+    }
+
 
-    text.append("tspan")
-        .text(`Jugadores: ${d.players}`)
-        .attr("x", cx + visualOffsetX + 10)
-        .attr("dy", "1.2em")
-        .style("opacity", 0)
-        .transition()
-        .duration(rectAparitionTime)
-        .ease(d3.easeQuadOut)
-        .style("opacity", 1)
 
     // Usa el bounding box del texto para calcular el tamaño del rectángulo
     const bbox = text.node().getBBox();
@@ -303,6 +318,8 @@ function handleMouseOver(event, d) {
                 return colores[selection][d[selection]];
             } else return "#aaaaaa";
         })
+        .style("stroke", "black")
+        .style("stroke-width", "3px")
         .attr("rx", 5)
         .attr("ry", 5)
         .style("opacity", 0)
@@ -343,8 +360,6 @@ function zoomed(event) {
     newXScale.domain([Math.max(min_x, newXScale.domain()[0]), Math.min(max_x, newXScale.domain()[1])]);
     newYScale.domain([Math.max(min_y, newYScale.domain()[0]), Math.min(max_y, newYScale.domain()[1])]);
 
-
-
     translate_group.select(".xAxis").call(d3.axisBottom(newXScale));
     translate_group.select(".yAxis").call(d3.axisLeft(newYScale));
 
@@ -364,8 +379,54 @@ function zoomed(event) {
 }
 
 function createBubbles(data) {
+    removeLegend();
+    const showNoData = () => {
+        svg.append('text')
+            .attr('x', width - right_margin + 1.2*margin_x)
+            .attr('y', 2*margin_y)
+            .attr('class', 'no-shown-data-text')
+            .text("No hay datos para los filtros seleccionados")
+            .style("font-size", "18px")
+            .style("font-family", "Georgia, serif")
+            .style("font-weight", "bold")
+            .attr('fill', 'red')
+    }
+
+    svg.select('.no-shown-data-text').remove();
+
+    if(data.length === 0){
+        showNoData();
+        return;
+    }
+
+
     const bubbleGroup = scatter.append('g')
         .attr('class', 'bubbles');
+    let newXScale, newYScale;
+
+    if(transform){
+        newXScale = transform.rescaleX(xScale);
+        newYScale = transform.rescaleY(yScale);
+
+        newXScale.domain([Math.max(min_x, newXScale.domain()[0]), Math.min(max_x, newXScale.domain()[1])]);
+        newYScale.domain([Math.max(min_y, newYScale.domain()[0]), Math.min(max_y, newYScale.domain()[1])]);
+
+        translate_group.select(".xAxis").call(d3.axisBottom(newXScale));
+        translate_group.select(".yAxis").call(d3.axisLeft(newYScale));
+
+        contentGroup.selectAll('.vertical-grid')
+            .attr('x1', d => newXScale(d) + margin_x)
+            .attr('x2', d => newXScale(d) + margin_x)
+
+        contentGroup.selectAll('.horizontal-grid')
+            .attr('y1', d => newYScale(d) + margin_y)
+            .attr('y2', d => newYScale(d) + margin_y)
+    } else {
+        newXScale = xScale;
+        newYScale = yScale;
+    }
+
+    let selectedColors = [];
 
     const zoom = d3.zoom()
         .scaleExtent([1, 10])
@@ -377,13 +438,17 @@ function createBubbles(data) {
         .data(data)
         .enter()
         .append("circle")
-        .attr("cx", d => xScale(d["user score"]) + margin_x)
-        .attr("cy", d => yScale(d["score"]) + margin_y)
+        .attr("cx", d => newXScale(d["user score"]) + margin_x)
+        .attr("cy", d => newYScale(d["score"]) + margin_y)
         .attr("r",  d => radiusScale(d["critics"]))
         .attr("fill", d => {
             if (colores[selection][d[selection]]){
+                selectedColors.push([d[selection], colores[selection][d[selection]]])
                 return colores[selection][d[selection]];
-            } else return "#aaaaaa";
+            } else{
+                selectedColors.push(["Otros", "#aaaaaa"]);
+                return "#aaaaaa";
+            }
         })
         .attr("stroke", "#000000")
         .attr("stroke-width", 1)
@@ -393,6 +458,19 @@ function createBubbles(data) {
 
     svg.call(zoom);
 
+    const unique = (vector) => {
+        const conjunto = new Set(
+            vector.map((elemento) => JSON.stringify(elemento))
+        );
+        return Array.from(conjunto).map((elemento) => JSON.parse(elemento));
+    };
+
+    selectedColors = unique(selectedColors);
+    selectedColors.sort((a, b) => a[0].localeCompare(b[0], undefined, {sensitivity:"base"}));
+
+    console.log(selectedColors)
+    setLegend(selectedColors);
+
 }
 
 function removeBubbles() {
@@ -417,12 +495,14 @@ function generateFilters(data) {
         "Open-World",
         "Action",
         "Shooter",
-        "Arcade",
+        "First-Person",
         "2D",
         "3D",
         "Rhythm",
-        "Team",
-        "Roguelike"
+        "Gambling",
+        "Role-Playing",
+        "Survival",
+        "Horror"
     ];
 
     generos.forEach(value => {
@@ -446,8 +526,6 @@ function applyFilters(data) {
         .filter(input => input.checked)
         .map(input => input.value);
 
-
-    // Filtra los datos en base a los filtros seleccionados
     elegibleData = data.filter(d => {
         if (selectedFilters.length === 0) return true;
         for (filter of selectedFilters) {
@@ -471,6 +549,42 @@ function enableSearch(data){
 
         createBubbles(elegibleData);
     }
+}
+
+function setLegend(entries){
 
+    // Crear grupos para cada elemento de la leyenda
+    const legend = svg.selectAll(".legend-item")
+        .data(entries)
+        .enter()
+        .append("g")
+        .attr("class", "legend-item")
+        .attr("transform", (d, i) =>{
+            if(i > 7){
+                return `translate(${width-right_margin + 4*margin_x}, ${(i-8) * 23 + height - 2.6 * margin_y})`
+            }
+            return `translate(${width-right_margin + 1.2*margin_x}, ${i * 23 + height - 2.6 * margin_y})`
+        });
+
+    // Dibujar los rectángulos de color
+    legend.append("rect")
+        .attr("width", 20)
+        .attr("height", 20)
+        .attr("fill", d => d[1])
+        .attr("rx", 2)
+        .attr("ry", 2)
+        .attr("stroke", "black")
+        .attr("stroke-width", 1.5)
+
+    // Agregar los textos descriptivos
+    legend.append("text")
+        .attr("x", 30)
+        .attr("y", 15)
+        .style("font-size", "16px")
+        .style("font-family", "Georgia, serif")
+        .text(d => d[0]);
 }
 
+function removeLegend(){
+    svg.selectAll('.legend-item').remove();
+}
\ No newline at end of file