Overview

Row

Total Propiedades

3722

Precio Promedio por m²

USD 254.97

Precio Mediano Total

USD 75,000

Superficie Promedio

703 m²

Row

Mapa Interactivo de Propiedades

Análisis de Precios

Row

Distribución de Precios Totales

Distribución de Precio por m²

Row

Relación Superficie vs Precio

Precio por m² según Rango de Superficie

Por Zona

Row

Top 10 Zonas por Precio Promedio

Número de Propiedades por Zona

Row

Boxplot de Precios por Zona (Top 10)

Datos

Row

Tabla Completa de Propiedades

Estadísticas

Row

Resumen General

Estadística Valor
Total Propiedades 3,722.00
Precio Promedio USD 146,769.33
Precio Mediano USD 75,000.00
Precio Mínimo USD 5,300.00
Precio Máximo USD 3,000,000.00
Precio/m² Promedio USD 254.97
Precio/m² Mediano USD 119.33
Superficie Promedio (m²) 703.11
Superficie Mediana (m²) 603.00

Por Rango de Precio

rango_precio Cantidad % del Total Superficie Promedio (m²) Precio/m² Promedio (USD)
< $50k 1190 32.0 471 79.77
$50k-$100k 1331 35.8 641 137.22
$100k-$200k 469 12.6 657 359.26
$200k-$500k 560 15.0 899 622.13
> $500k 172 4.6 2276 898.47

Por Rango de Superficie

rango_m2 Cantidad % del Total Precio Promedio (USD) Precio/m² Promedio (USD)
< 500m² 1449 38.9 110,803 359.36
500-1000m² 1980 53.2 130,964 185.20
1000-2000m² 207 5.6 304,618 230.35
2000-5000m² 51 1.4 660,305 210.06
> 5000m² 35 0.9 848,057 90.90
---
title: "Monitor de Precios del Suelo - Mar del Plata"
output: 
  flexdashboard::flex_dashboard:
    orientation: rows
    vertical_layout: fill
    theme: cosmo
    source_code: embed
---

```{r setup, include=FALSE}
library(flexdashboard)
library(tidyverse)
library(leaflet)
library(plotly)
library(DT)
library(scales)

# Cargar los datos
# Si ya tienes tabla_zonaprop_filter en el ambiente, úsalo directamente
tabla_zonaprop_filter <- readRDS("F:/RSTUDIO/terrenos/data/tabla_zonaprop_filter.rds")
# Limpiar datos (eliminar coordenadas no válidas)
datos <- tabla_zonaprop_filter %>%
  filter(!coordenadas %in% c("No disponible", "Sin coordenadas", "Offline", "Error", NA)) %>%
  filter(!is.na(lat) & !is.na(long)) %>%
  filter(precio > 0 & m2ok > 0 & precio_m2 > 0)

# Crear categorías de precio
datos <- datos %>%
  mutate(
    rango_precio = cut(precio, 
                       breaks = c(0, 50000, 100000, 200000, 500000, Inf),
                       labels = c("< $50k", "$50k-$100k", "$100k-$200k", "$200k-$500k", "> $500k")),
    rango_m2 = cut(m2ok,
                   breaks = c(0, 500, 1000, 2000, 5000, Inf),
                   labels = c("< 500m²", "500-1000m²", "1000-2000m²", "2000-5000m²", "> 5000m²"))
  )
```

# Overview

## Row {data-height=150}

### Total Propiedades
```{r}
valueBox(
  nrow(datos),
  icon = "fa-home",
  color = "primary"
)
```

### Precio Promedio por m²
```{r}
valueBox(
  paste0("USD ", round(mean(datos$precio_m2, na.rm = TRUE), 2)),
  icon = "fa-dollar-sign",
  color = "success"
)
```

### Precio Mediano Total
```{r}
valueBox(
  paste0("USD ", format(median(datos$precio, na.rm = TRUE), big.mark = ",")),
  icon = "fa-chart-line",
  color = "info"
)
```

### Superficie Promedio
```{r}
valueBox(
  paste0(round(mean(datos$m2ok, na.rm = TRUE), 0), " m²"),
  icon = "fa-ruler-combined",
  color = "warning"
)
```

## Row {data-height=850}

### Mapa Interactivo de Propiedades
```{r}
# Paleta de colores según precio por m²
pal <- colorNumeric(
  palette = "YlOrRd",
  domain = datos$precio_m2
)

# Crear el mapa
leaflet(datos) %>%
  addProviderTiles(providers$CartoDB.Positron) %>%
  addCircleMarkers(
    lng = ~long,
    lat = ~lat,
    radius = ~sqrt(m2ok) / 10,
    color = ~pal(precio_m2),
    fillOpacity = 0.7,
    stroke = TRUE,
    weight = 1,
    popup = ~paste0(
      "<b>Ubicación:</b> ", loc2, "<br>",
      "<b>Precio:</b> USD ", format(precio, big.mark = ","), "<br>",
      "<b>Superficie:</b> ", m2ok, " m²<br>",
      "<b>Precio/m²:</b> USD ", round(precio_m2, 2), "<br>",
      "<b>Dirección:</b> ", loc1, "<br>",
      "<a href='", link, "' target='_blank'>Ver publicación</a>"
    ),
    label = ~paste0(loc2, " - USD ", format(precio, big.mark = ","))
  ) %>%
  addLegend(
    position = "bottomright",
    pal = pal,
    values = ~precio_m2,
    title = "Precio por m²<br>(USD)",
    opacity = 1
  ) %>%
  setView(lng = -57.57, lat = -38.00, zoom = 11)
```

# Análisis de Precios

## Row

### Distribución de Precios Totales
```{r}
p1 <- ggplot(datos, aes(x = precio)) +
  geom_histogram(bins = 50, fill = "#3498db", alpha = 0.7) +
  scale_x_continuous(labels = dollar_format(prefix = "USD ")) +
  labs(
    title = "Distribución de Precios",
    x = "Precio Total (USD)",
    y = "Frecuencia"
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

ggplotly(p1)
```

### Distribución de Precio por m²
```{r}
p2 <- ggplot(datos, aes(x = precio_m2)) +
  geom_histogram(bins = 50, fill = "#e74c3c", alpha = 0.7) +
  scale_x_continuous(labels = dollar_format(prefix = "USD ")) +
  labs(
    title = "Distribución de Precio por m²",
    x = "Precio por m² (USD)",
    y = "Frecuencia"
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

ggplotly(p2)
```

## Row

### Relación Superficie vs Precio
```{r}
p3 <- ggplot(datos, aes(x = m2ok, y = precio, color = precio_m2)) +
  geom_point(alpha = 0.6, size = 2) +
  scale_color_gradient(low = "#2ecc71", high = "#e74c3c", name = "Precio/m²") +
  scale_x_continuous(labels = comma_format()) +
  scale_y_continuous(labels = dollar_format(prefix = "USD ")) +
  labs(
    title = "Relación entre Superficie y Precio",
    x = "Superficie (m²)",
    y = "Precio Total (USD)"
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

ggplotly(p3)
```

### Precio por m² según Rango de Superficie
```{r}
p4 <- datos %>%
  group_by(rango_m2) %>%
  summarise(
    precio_m2_medio = mean(precio_m2, na.rm = TRUE),
    n = n()
  ) %>%
  ggplot(aes(x = rango_m2, y = precio_m2_medio, fill = rango_m2)) +
  geom_col(alpha = 0.8) +
  geom_text(aes(label = paste0("n=", n)), vjust = -0.5, size = 3) +
  scale_y_continuous(labels = dollar_format(prefix = "USD ")) +
  scale_fill_brewer(palette = "Set2") +
  labs(
    title = "Precio Promedio por m² según Superficie",
    x = "Rango de Superficie",
    y = "Precio Promedio por m² (USD)"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    legend.position = "none",
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

ggplotly(p4)
```

# Por Zona

## Row

### Top 10 Zonas por Precio Promedio
```{r}
top_zonas <- datos %>%
  group_by(loc2) %>%
  summarise(
    precio_promedio = mean(precio, na.rm = TRUE),
    precio_m2_promedio = mean(precio_m2, na.rm = TRUE),
    n_propiedades = n()
  ) %>%
  filter(n_propiedades >= 5) %>%
  arrange(desc(precio_m2_promedio)) %>%
  head(10)

p5 <- ggplot(top_zonas, aes(x = reorder(loc2, precio_m2_promedio), y = precio_m2_promedio)) +
  geom_col(aes(fill = precio_m2_promedio), alpha = 0.8) +
  geom_text(aes(label = paste0("n=", n_propiedades)), hjust = -0.2, size = 3) +
  scale_y_continuous(labels = dollar_format(prefix = "USD ")) +
  scale_fill_gradient(low = "#3498db", high = "#e74c3c", name = "Precio/m²") +
  coord_flip() +
  labs(
    title = "Top 10 Zonas por Precio/m² (mín. 5 propiedades)",
    x = "",
    y = "Precio Promedio por m² (USD)"
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

ggplotly(p5)
```

### Número de Propiedades por Zona
```{r}
zonas_count <- datos %>%
  count(loc2, sort = TRUE) %>%
  head(15)

p6 <- ggplot(zonas_count, aes(x = reorder(loc2, n), y = n)) +
  geom_col(fill = "#9b59b6", alpha = 0.8) +
  coord_flip() +
  labs(
    title = "Top 15 Zonas con Más Propiedades",
    x = "",
    y = "Número de Propiedades"
  ) +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5, face = "bold"))

ggplotly(p6)
```

## Row

### Boxplot de Precios por Zona (Top 10)
```{r}
top_10_zonas <- datos %>%
  count(loc2, sort = TRUE) %>%
  head(10) %>%
  pull(loc2)

datos_top <- datos %>%
  filter(loc2 %in% top_10_zonas)

p7 <- ggplot(datos_top, aes(x = reorder(loc2, precio_m2, FUN = median), y = precio_m2, fill = loc2)) +
  geom_boxplot(alpha = 0.7, outlier.alpha = 0.5) +
  scale_y_continuous(labels = dollar_format(prefix = "USD ")) +
  coord_flip() +
  labs(
    title = "Distribución de Precio/m² por Zona",
    x = "",
    y = "Precio por m² (USD)"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    legend.position = "none"
  )

ggplotly(p7)
```

# Datos

## Row

### Tabla Completa de Propiedades
```{r}
datos %>%
  select(
    Zona = loc2,
    Dirección = loc1,
    `Precio (USD)` = precio,
    `Superficie (m²)` = m2ok,
    `Precio/m² (USD)` = precio_m2,
    Link = link
  ) %>%
  mutate(
    `Precio (USD)` = format(`Precio (USD)`, big.mark = ","),
    `Precio/m² (USD)` = round(`Precio/m² (USD)`, 2),
    Link = paste0('<a href="', Link, '" target="_blank">Ver</a>')
  ) %>%
  datatable(
    escape = FALSE,
    filter = "top",
    options = list(
      pageLength = 25,
      scrollX = TRUE,
      autoWidth = TRUE,
      columnDefs = list(list(width = '200px', targets = c(0, 1)))
    ),
    rownames = FALSE
  )
```

# Estadísticas

## Row {.tabset}

### Resumen General
```{r}
resumen <- datos %>%
  summarise(
    `Total Propiedades` = n(),
    `Precio Promedio` = mean(precio, na.rm = TRUE),
    `Precio Mediano` = median(precio, na.rm = TRUE),
    `Precio Mínimo` = min(precio, na.rm = TRUE),
    `Precio Máximo` = max(precio, na.rm = TRUE),
    `Precio/m² Promedio` = mean(precio_m2, na.rm = TRUE),
    `Precio/m² Mediano` = median(precio_m2, na.rm = TRUE),
    `Superficie Promedio (m²)` = mean(m2ok, na.rm = TRUE),
    `Superficie Mediana (m²)` = median(m2ok, na.rm = TRUE)
  ) %>%
  pivot_longer(everything(), names_to = "Estadística", values_to = "Valor") %>%
  mutate(Valor = ifelse(grepl("Precio", Estadística), 
                        paste0("USD ", format(round(Valor, 2), big.mark = ",")),
                        format(round(Valor, 2), big.mark = ",")))

knitr::kable(resumen, align = c("l", "r"))
```

### Por Rango de Precio
```{r}
resumen_rango <- datos %>%
  group_by(rango_precio) %>%
  summarise(
    `Cantidad` = n(),
    `% del Total` = round(n() / nrow(datos) * 100, 1),
    `Superficie Promedio (m²)` = round(mean(m2ok, na.rm = TRUE), 0),
    `Precio/m² Promedio (USD)` = round(mean(precio_m2, na.rm = TRUE), 2)
  ) %>%
  arrange(rango_precio)

knitr::kable(resumen_rango, align = c("l", "r", "r", "r", "r"))
```

### Por Rango de Superficie
```{r}
resumen_m2 <- datos %>%
  group_by(rango_m2) %>%
  summarise(
    `Cantidad` = n(),
    `% del Total` = round(n() / nrow(datos) * 100, 1),
    `Precio Promedio (USD)` = format(round(mean(precio, na.rm = TRUE), 0), big.mark = ","),
    `Precio/m² Promedio (USD)` = round(mean(precio_m2, na.rm = TRUE), 2)
  ) %>%
  arrange(rango_m2)

knitr::kable(resumen_m2, align = c("l", "r", "r", "r", "r"))
```