Colaje de imágenes

Experimento con R y algo de magick

R
rinat
magick
Español
Author

José R. Ferrer-Paris

Published

April 1, 2025

Modified

August 30, 2025

Herramientas y paquetes

En este caso voy a usar R con una selección de mis paquetes favoritos, pero en uno de los pasos necesito acceder a funciones de image magick fuera del entorno de R.

Esta es la lista de paquetes usados en este artículo:

library(rinat)
library(dplyr)
library(lubridate)
library(magick)
library(foreach)
library(kableExtra)
  • rinat: Acceso a datos de iNaturalist desde R.

  • magick: Magick Image Processing.

  • foreach: Mi función favorita para hacer bucles.

  • dplyr: Para la preparación de datos con estilo.

Uso el paquete here para declarar la ruta de acceso de los archivos:

here::i_am("neomapas/collage.qmd")

Con esto preparamos las carpetas que van a contener los archivos que vamos a descargar y generar.

if (!dir.exists(here::here("data")))
    dir.create(here::here("data"))
if (!dir.exists(here::here("img")))
    dir.create(here::here("img"))
inat_obs_data <- here::here("data", "inat-obs.rds")
inat_obs_img <- here::here("img", "inat-collage.png")

Ahora, descargamos la lista de observaciones de mi usuario en iNaturalist. Guardo los resultados en la carpeta data:

if (file.exists(inat_obs_data)) {
    user_obs <- readRDS(inat_obs_data)
} else {
    user_obs <- get_inat_obs_user("NeoMapas",maxresults = 5000) |> 
        mutate(dts=date(datetime), year=year(dts), month=month(dts))
    saveRDS(user_obs, inat_obs_data)
}

¿Cuál es la fecha de mi primera observación en iNat?

(first_obs <- user_obs |> arrange(dts) |> slice_head(n=1) |> pull(dts))
[1] "2004-04-13"

El tiempo que llevo en iNat:

tiempo_inat <- interval(first_obs,lubridate::today() )
sprintf("%0.1f",time_length(tiempo_inat, 'years')) |>
    cat()
21.4

El número total de observaciones:

nrow(user_obs)
[1] 1822

Y el número aproximado de taxones representados en estas observaciones:

n_distinct(user_obs$species_guess)
[1] 1198

Para imprimir una tabla con las observaciones por año puedo usar este código:

user_obs |> 
    group_by(year) |>
    summarise(
        `Meses con observaciones` = n_distinct(month),
        `Días con observaciones` = n_distinct(dts),
        `Número total de observaciones` = n()
    ) |> kbl()
year Meses con observaciones Días con observaciones Número total de observaciones
2004 4 10 16
2005 9 34 84
2006 7 48 188
2007 3 6 16
2008 8 18 66
2009 6 16 54
2010 3 16 127
2012 3 4 11
2013 1 2 5
2014 6 17 51
2015 8 19 26
2016 4 9 34
2017 4 5 8
2018 5 11 14
2019 6 13 25
2020 9 21 92
2021 10 30 71
2022 12 46 150
2023 10 50 199
2024 12 74 311
2025 8 51 274

Uso éste código para crear un colaje de mis observaciones a lo largo de los años:

if (file.exists(inat_obs_img)) {
    iNat_collage <- image_read(inat_obs_img)
} else {
    YearsRowImages <- foreach (slc_year=rev(sort(unique(user_obs$year))), .combine=c) %do% {
        ejemplos <- user_obs |> 
            filter(year==slc_year, quality_grade == 'research') |>
            mutate(seleccion=!duplicated(month)) |>
            filter(seleccion) |>
            arrange(month)
        poxs <- foreach(j=1:nrow(ejemplos), .combine = c) %do% {
            pix <- 
                slice(ejemplos,j) |> 
                #mutate(simage=gsub('medium', 'square',image_url)) |> # the square image has a lower resolution
                pull(image_url) |>
                image_read() |> 
                image_resize(geometry_size_pixels(200)) |>
                image_write('input.png')
            system('magick input.png -gravity center \\( -size 135x135 xc:black -fill white -draw "circle 60 60 60 0" -alpha copy \\) -compose copyopacity -composite output.png')
            pox <- image_read('output.png') |> image_trim()
            mnm <- month.abb[slice(ejemplos,j) |> pull(month)]
            pox_text <- image_annotate(pox, mnm, size=20,color='white', gravity='southeast', location = "+35+10 ")
            return(pox_text)
        }
        rowImages <- image_append(poxs)
        YearRowImages <- image_annotate(rowImages, sprintf("Year %s", slc_year), 
                                        size = 25, gravity = "northwest", color = "white", #boxcolor = "pink",
                                    degrees = -90, location = "-29+119 ") |> 
                        image_annotate(sprintf("Year %s", slc_year), 
                                        size = 25, gravity = "northwest", color = "black", #boxcolor = "pink",
                                    degrees = -90, location = "-30+120")
        return(YearRowImages)

        }
    iNat_collage <- image_append(YearsRowImages, stack = TRUE)
    image_write(iNat_collage, path = inat_obs_img)
    system("rm input.png output.png")
}
iNat_collage