milos-agathon / mapping-river-basins-with-r

In this tutorial, I will show you how to use HydroSHEDS data to create a beautiful and informative map of Brazil’s river basins. You will learn how to download, process and visualize the HydroSHEDS data
22 stars 2 forks source link

the condition has length > 1 #3

Open vin-ni opened 10 months ago

vin-ni commented 10 months ago

Hello, I've been trying to run the code, but there seems to be an error. I tried forcing each of the shapefiles by hardcoding them, but it still doesnt work. Do you have an idea what could be the problem? Unfortunately I'm not super familiar with R.

Thank you!

I attached the full log:

> ###################################################
> #                 Mapping river basins with R
> #                 Milos Popovic
> #                 2023/07/07
> ###################################################
> libs <- c(
+     "tidyverse", "sf",
+     "giscoR"
+ )
> installed_libraries <- libs %in% rownames(
+     installed.packages()
+ )
> if (any(installed_libraries == F)) {
+     install.packages(
+         libs[!installed_libraries]
+     )
+ }
> invisible(
+     lapply(
+         libs, library,
+         character.only = T
+     )
+ )
── Attaching core tidyverse packages ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.4.4     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.0
✔ purrr     1.0.2     
── Conflicts ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package to force all conflicts to become errors
Linking to GEOS 3.11.0, GDAL 3.5.3, PROJ 9.1.0; sf_use_s2() is TRUE
> # 1. GET COUNTRY BORDERS
> #-----------------------
> print("GET COUNTRY BORDERS")
[1] "GET COUNTRY BORDERS"
> get_country_borders <- function() {
+     country_borders <- giscoR::gisco_get_countries(
+         resolution = "3",
+         country = "US"
+     )
+ 
+     return(country_borders)
+ }
> country_borders <- get_country_borders()
> # 2. GET BASINS
> #---------------
> print("GET BASINS")
[1] "GET BASINS"
> get_basins <- function() {
+     url <- "https://data.hydrosheds.org/file/HydroBASINS/standard/hybas_na_lev03_v1c.zip"
+     file_name <- "hybas_na_lev03_v1c.zip"
+ 
+     download.file(
+         url = url,
+         destfile = file_name,
+         mode = "wb"
+     )
+ 
+     unzip(file_name)
+ }
> get_basins()
trying URL 'https://data.hydrosheds.org/file/HydroBASINS/standard/hybas_na_lev03_v1c.zip'
Content type 'application/zip' length 3728058 bytes (3.6 MB)
==================================================
downloaded 3.6 MB

> print("basin downloaded")
[1] "basin downloaded"
> list.files()
 [1] "hybas_na_lev03_v1c.dbf"      "hybas_na_lev03_v1c.prj"      "hybas_na_lev03_v1c.sbn"      "hybas_na_lev03_v1c.sbx"      "hybas_na_lev03_v1c.shp"     
 [6] "hybas_na_lev03_v1c.shp.xml"  "hybas_na_lev03_v1c.shx"      "hybas_na_lev03_v1c.zip"      "HydroBASINS_TechDoc_v1c.pdf" "HydroRIVERS_TechDoc_v10.pdf"
[11] "HydroRIVERS_v10_na_shp"      "main.r"                      "na-rivers.zip"               "R.Rproj"                    
> print("load basin")
[1] "load basin"
> load_basins <- function() {
+     print("loading filenames")
+     filenames <- list.files(
+         pattern = ".shp$",
+         full.names = TRUE
+     )
+     print(filenames)
+     namerica_basin <- sf::st_read(
+         filenames
+     )
+ 
+     return(namerica_basin)
+ }
> namerica_basin <- load_basins()
[1] "loading filenames"
[1] "./hybas_na_lev03_v1c.shp" "./HydroRIVERS_v10_na_shp"
Error in if (nchar(dsn) < 1) stop("`dsn` must point to a source, not an empty string.",  : 
  the condition has length > 1
3.
st_read.character(filenames)
2.
sf::st_read(filenames)
1.
load_basins()
vin-ni commented 10 months ago

I've gotten closer. I think this happens when there are several shp files / if the files are already downloaded. If I delete all downloads and run the whole thing, it works. Here's an example for france:

###################################################
#                 Mapping river basins with R
#                 Milos Popovic
#                 2023/07/07
###################################################
libs <- c(
    "tidyverse", "sf",
    "giscoR"
)

installed_libraries <- libs %in% rownames(
    installed.packages()
)

if (any(installed_libraries == F)) {
    install.packages(
        libs[!installed_libraries]
    )
}

invisible(
    lapply(
        libs, library,
        character.only = T
    )
)

# 1. GET COUNTRY BORDERS
#-----------------------
print("GET COUNTRY BORDERS")
get_country_borders <- function() {
    country_borders <- giscoR::gisco_get_countries(
        resolution = "1",
        country = "FRANCE"
    )

    return(country_borders)
}

country_borders <- get_country_borders()

# 2. GET BASINS
#---------------
print("GET BASINS")
# https://data.hydrosheds.org/file/HydroBASINS/standard/hybas_sa_lev03_v1c.zip

get_basins <- function() {
    url <- "https://data.hydrosheds.org/file/hydrobasins/standard/hybas_eu_lev03_v1c.zip"
    file_name <- "hybas_na_lev03_v1c.zip"

    download.file(
        url = url,
        destfile = file_name,
        mode = "wb"
    )

    unzip(file_name)
}

get_basins()
print("basin downloaded")

list.files()

print("load basin")
load_basins <- function() {
    print("loading filenames")
    filenames <- list.files(
        pattern = ".shp$",
        full.names = TRUE
    )
    print(filenames)
    namerica_basin <- sf::st_read(
        filenames
    )

    return(namerica_basin)
}

namerica_basin <- load_basins()
print("basin loaded")

print("Intersect Basin with only the wanted Country Boundary.")
sf::sf_use_s2(F)

brazil_basin <- namerica_basin |>
    sf::st_intersection(
        country_borders
    ) |>
    dplyr::select(
        HYBAS_ID
    )

# 3. GET RIVERS DATA
#-------------------
print("Get Rivers")
# https://data.hydrosheds.org/file/HydroRIVERS/HydroRIVERS_v10_sa_shp.zip
# https://data.hydrosheds.org/file/HydroRIVERS/HydroRIVERS_v10_eu_shp.zip
get_rivers <- function() {
    url <- "https://data.hydrosheds.org/file/HydroRIVERS/HydroRIVERS_v10_eu_shp.zip"
    file_name <- "na-rivers.zip"

    download.file(
        url = url,
        destfile = file_name,
        mode = "wb"
    )

    unzip(file_name)
}

get_rivers()
print("Getting Rivers")
list.files()

load_rivers <- function() {
    filenames <- list.files(
        path = "HydroRIVERS_v10_eu_shp",
        pattern = ".shp$",
        full.names = T
    )
    print(filenames)
    namerica_rivers <- sf::st_read(
        filenames
    )

    return(namerica_rivers)
}

namerica_rivers <- load_rivers()

brazil_rivers <- namerica_rivers |>
    dplyr::select(
        ORD_FLOW
    ) |>
    sf::st_intersection(
        country_borders
    )

# 4. DETERMINE BASIN FOR EVERY RIVER
#-----------------------------------

brazil_river_basin <- sf::st_intersection(
    brazil_rivers,
    brazil_basin
)

# 5. RIVER WIDTH
#---------------

unique(brazil_river_basin$ORD_FLOW)

brazil_river_basin_width <- brazil_river_basin |>
    dplyr::mutate(
        width = as.numeric(
            ORD_FLOW
        ),
        width = dplyr::case_when(
            width == 1 ~ .8,
            width == 2 ~ .7,
            width == 3 ~ .6,
            width == 4 ~ .45,
            width == 5 ~ .35,
            width == 6 ~ .25,
            width == 7 ~ .2,
            width == 8 ~ .15,
            width == 9 ~ .1,
            TRUE ~ 0
        )
    ) |>
    sf::st_as_sf()

# 6. PLOT
#--------

unique(
    brazil_river_basin_width$HYBAS_ID
)

hcl.pals("qualitative")

p <- ggplot() +
    geom_sf(
        data = brazil_river_basin_width,
        aes(
            color = factor(
                HYBAS_ID
            ),
            size = width,
            alpha = width
        )
    ) +
    scale_color_manual(
        name = "",
        values = hcl.colors(
            17, "Dark 3",
            alpha = 1
        )
    ) +
    scale_size(
        range = c(.1, .7)
    ) +
    scale_alpha(
        range = c(.01, .7)
    ) +
    theme_void() +
    theme(
        legend.position = "none",
        plot.caption = element_text(
            size = 9, color = "grey60",
            hjust = .1, vjust = 10
        ),
        plot.margin = unit(
            c(
                t = 0, r = 0,
                b = 0, l = 0
            ),
            "lines"
        ),
        plot.background = element_rect(
            fill = "black",
            color = NA
        ),
        panel.background = element_rect(
            fill = "black",
            color = NA
        )
    ) +
    labs(
        title = "",
        x = "",
        y = "",
        # caption = "Source: ©World Wildlife Fund, Inc. (2006-2013) HydroSHEDS database http://www.hydrosheds.org"
    )

ggsave(
    filename = "us-river-basins.png",
    width = 7, height = 7.75, dpi = 600,
    bg = "white", device = "png", p
)

st_write(brazil_river_basin_width, "us-river-basins.geojson", layer = NULL, driver = "GeoJson")