Extensão da rede

Evolução da rede ciclável em Lisboa


Extensão das ciclovias por ano




Nota: É possível esconder ou mostrar tipologias clicando no item da legenda.
As Não dedicadas são essencialmente 30+bici

A informação disponibilizada neste site não deve ser encarada como fonte de informação oficial

Esta dashboard pretende ser um exercício de recolha, tratamento e visualização de dados, utilizando software open-source (R software).
Esta App utiliza os seguintes packages: shiny, sf, leaflet, dplyr, ggplot2, plotly, units, rmarkdown.

Dados

A informação sobre as ciclovias foi recolhida através do portal de geodados da Câmara Municipal de Lisboa, que mantém esta base de dados actualizada com regularidade.
última actualização: 22.Março.2026

O ano de construção e tipologias foram depois acertadas, tal como desrito no código-fonte. São também apresentadas ciclovias que deixaram de existir ou que foram corrigidas, tais como:

  • Campo Grande - Telheiras, anterior à construção do Estádio de Alvalade
  • Bici+BUS na Avenida da Liberdade, antes de passarem paras as laterais
  • Braço de Prata - Matinha, reformulação do traçado
  • Avenida Almirante Reis, reformulação do traçado
  • Avenida de Berna, reformulação do traçado
  • Passeio de Neptuno e ligação Av dos Oceanos, reformulação do traçado

Créditos

Este site foi desenvolvido por Rosa Félix, investigadora na área da mobilidade ciclável no U-Shift lab, do CERIS, no Instituto Superior Técnico - Universidade de Lisboa.

Algo está errado?

Falta alguma ciclovia? Há um troço mal classificado? A ciclovia não foi construída naquele ano?
Deixa os teus comentários em https://github.com/U-Shift/RedeCiclavel-Lisboa/issues

Obrigada!

knitr::opts_chunk$set(echo = TRUE)
library(rmarkdown)

Importação dos dados

Importar packages R

library(tidyverse)
library(sf)
library(mapview)
library(units)
library(cartography)

Importar rede ciclável

Download da informação geoffererenciada a partir do servidor da CML: https://services.arcgis.com/1dSrzEWVQn5kHHyK/arcgis/rest/services/Ciclovias/FeatureServer/0/query?outFields=*&where=1%3D1&f=geojson

CicloviasAnteriores = readRDS("CicloviasAnos/CicloviasAnos.Rds")
Ciclovias2025 = st_read("https://services.arcgis.com/1dSrzEWVQn5kHHyK/arcgis/rest/services/Ciclovias/FeatureServer/0/query?outFields=*&where=1%3D1&f=geojson")
length(unique(Ciclovias2025$OBJECTID)) #1069
length(unique(Ciclovias2025$COD_SIG)) #1041

Corrigir dados

#filtrar só últimos anos
Ciclovias2025 = Ciclovias2025 %>% filter(ANO == "2025")

#exportar e abrir no sig
st_write(Ciclovias2025, "data/Ciclovias2025_dez_cml.gpkg", delete_dsn = TRUE)

Importar novamente o shp atualizado

Ciclovias2025_new = st_read("data/Ciclovias2025_corrigir.gpkg", layer = "ciclovias2025")
Ciclovias2025_new = Ciclovias2025_new |> filter(is.na(AnoT)) |> filter(ANO == 2025)

Neste caso adicionou-se:

  • Álvaro Pais
  • Avenida Santos Durmont
  • Ponte Rotunda do Relógio
  • Praça do Comércio (30 + bici)
  • Av Glicínia Quartin (sta Clara)
  • Bairro Madre de Deus (30 + bici)
  • Rua Nossa Sra. Amparo (30 + bici)
  • Bairro do Restelo (30 + bici)
  • Continuação Av de Paris e bairro dos Actores (30 + bici)
  • São Sebastião da Pedreira (30 + bici)
  • Praça da Figueira
  • Bairro Campolide (30 + bici)
  • Campo de Ourique (30 + bici)
  • Bairro da Serafina (30 + bici)
  • R Marques da Silva troço (30 + bici)

Reclassificar ciclovias

Em dedicadas (uni e bi-direccionais, pistas cicláveis) e não-dedicadas (30+bici, zona de coexistência), e percursos em coexistência com o peão (ciclo-pedonal)

table(Ciclovias2025_new$TIPOLOGIA)

Ciclovias2025_new = Ciclovias2025_new |> 
  mutate(TIPOLOGIA = case_when(
    TIPOLOGIA == "Percurso Ciclopedonal" ~ "Percurso Ciclo-pedonal",
    
    TIPOLOGIA %in% c(
      "Pista Ciclavel Bidirecional", 
      "Pista Ciclável Bidirecional", 
      "Pista Ciclável Unidirecional", 
      "Pista ciclável (ciclovia)", 
      "Contrassentido", 
      "Faixa Ciclável"
    ) ~ "Ciclovia dedicada",
    
    TIPOLOGIA %in% c("30+Bici", "Zona de Coexistência") ~ "Nao dedicada",
    
    TRUE ~ as.character(TIPOLOGIA) 
  ))

#factor tipologia
Ciclovias2025_new = Ciclovias2025_new |> mutate(TIPOLOGIA = factor(TIPOLOGIA))
table(Ciclovias2025_new$TIPOLOGIA)

Juntar novamente com as anteriores

#prolongar vida ultimos anos
CicloviasAnteriores_25 = CicloviasAnteriores %>% filter(AnoT == 2024) %>% mutate(AnoT = 2025)
CicloviasAnteriores = rbind(CicloviasAnteriores, CicloviasAnteriores_25)

#juntar, ignorando comprimento
Ciclovias = bind_rows(CicloviasAnteriores |> select(-lenght),
                      Ciclovias2025_new |> select(-lenght))

#remover duplicados
Ciclovias = distinct(Ciclovias)

# atribuir ID para ser mais fácil o corte e costura
Ciclovias = Ciclovias |> mutate(id = as.integer(row.names(Ciclovias)))
Ciclovias = Ciclovias |> mutate(AnoT = case_when(ANO == 2025 ~ 2025, TRUE ~ AnoT))


#recalcular geometria
Ciclovias$length = st_length(Ciclovias) %>% units::set_units(km)
sum(Ciclovias$length[Ciclovias$AnoT==2025]) #extensão da rede actual
# calma, há segmentos que foram destruídos entretanto

Ver num mapa

Todas as ciclovias que existem ou existiram no server da CML

mapview::mapview(Ciclovias, zcol="TIPOLOGIA", lwd=1.5, hide=F, legend=T)

Atualizar troços de ciclovias

  • Atualizou-se a ciclovia da Av das Nações Unidas (cortada).
  • Marquês de Pombal passou a ter outra configuração em 2013.
  • 30+Bici no Bairro do Rego desde 2018

Av Nações Unidas

Ciclovias_corrigir_trocos = st_read("data/Ciclovias2025_nacoesunidas.gpkg", layer="nacoesunidas")
Ciclovias_corrigir_trocos = Ciclovias_corrigir_trocos |> mutate(id = as.integer(row.names(Ciclovias_corrigir_trocos)))
#nacoesunidas - 1920 -> 2621 e 2622, era de 2019 e troço 2622 desaparece em 2025
#nacoesunidas - troço 3 desaparece em 2025
nacoes_id = 2334 # old
nacoes_novo_25 = Ciclovias_corrigir_trocos |> 
  filter(id %in% c(1,2)) |>
  mutate(AnoT = 2025,
         id = id + 9950) |> 
  select(-lenght)
nacoes_novo_25$length = st_length(nacoes_novo_25) %>% units::set_units(km)

Ciclovias = Ciclovias %>% filter(!(id %in% nacoes_id)) |> bind_rows(nacoes_novo_25)

Marquês de Pombal

Ciclovias_corrigir_trocos = st_read("data/Ciclovias2025_marques.gpkg", layer="marques")
marques_13 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2013, id = 99130+row_number())
marques_14 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2014, id = 99140+row_number())
marques_15 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2015, id = 99150+row_number())
marques_16 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2016, id = 99160+row_number())
marques_17 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2017, id = 99170+row_number())
marques_18 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2018, id = 99180+row_number())
marques_19 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2019, id = 99190+row_number())
marques_20 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2020, id = 99200+row_number())
marques_21 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2021, id = 99210+row_number())
marques_22 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2022, id = 99220+row_number())
marques_23 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2023, id = 99230+row_number())
marques_24 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2024, id = 99240+row_number())
marques_25 = Ciclovias_corrigir_trocos %>% mutate(AnoT = 2025, id = 99250+row_number())
marques = rbind(marques_13, marques_14, marques_15, marques_16, marques_17, marques_18, marques_19, marques_20, marques_21, marques_22, marques_23, marques_24, marques_25) |> 
  mutate(TIPOLOGIA = "Ciclovia dedicada")
marques$length = st_length(marques) %>% units::set_units(km)

marques_id = c(1327:1334, 1336, 1338, 1340, 1342, 2338, 2339)
Ciclovias = Ciclovias %>% filter(!(id %in% marques_id)) |> bind_rows(marques)

Bairro do Rego

Ciclovias_corrigir_trocos = st_read("data/Ciclovias2025_corrigir.gpkg", layer = "ciclovias2025")
rego_18 = Ciclovias_corrigir_trocos[483,]
rego_18 = rego_18 |> mutate(AnoT = 2018, id = 9968, TIPOLOGIA = "Nao dedicada")
rego_19 = rego_18 |> mutate(AnoT = 2019, id = 9969)
rego_20 = rego_18 |> mutate(AnoT = 2020, id = 9970)
rego_21 = rego_18 |> mutate(AnoT = 2021, id = 9971)
rego_22 = rego_18 |> mutate(AnoT = 2022, id = 9972)
rego_23 = rego_18 |> mutate(AnoT = 2023, id = 9973)
rego_24 = rego_18 |> mutate(AnoT = 2024, id = 9974)
rego_25 = rego_18 |> mutate(AnoT = 2025, id = 9975)
rego = rbind(rego_18, rego_19, rego_20, rego_21, rego_22, rego_23, rego_24, rego_25)
rego$length = st_length(rego) %>% units::set_units(km)

Ciclovias = Ciclovias |> bind_rows(rego)
rm(Ciclovias_corrigir_trocos, nacoes_novo_25, marques_13, marques_14, marques_15, marques_16, marques_17, marques_18, marques_19, marques_20, marques_21, marques_22, marques_23, marques_24, marques_25, marques,
   rego_18, rego_19, rego_20, rego_21, rego_22, rego_23, rego_24, rego_25, rego)

Confirmar mapa actual

cic25=Ciclovias[Ciclovias$AnoT==2025,]
# greens3 = cartography::carto.pal(pal1 = "green.pal", 3)
# greens3 = rev(greens3)
greens3 = c("#197230", "#5A9C50", "#B2D6A3")
mapview(cic25, zcol="TIPOLOGIA", color = greens3, lwd=2, hide=F, legend=T)

Adicionar contador de km

# recalcular extensão
Ciclovias$length = st_length(Ciclovias) %>% units::set_units(km)

#Adicionar campo com extensão da rede acumulada
CicloviasKM = Ciclovias %>% select(AnoT, length, TIPOLOGIA) %>% st_drop_geometry()

CicloviasKMnull = data.frame(TIPOLOGIA= c("Nao dedicada", "Nao dedicada"),
                             length=0, AnoT = c(2001,2002),stringsAsFactors=FALSE)
CicloviasKMnull$length = CicloviasKMnull$length %>% units::set_units(km)
CicloviasKM = rbind(CicloviasKM,CicloviasKMnull)

CicloviasKM = CicloviasKM  %>% group_by(AnoT, TIPOLOGIA) %>% summarise(length = sum(length, na.rm=TRUE)) %>% ungroup()

CicloviasKM$Kms <- paste(round(CicloviasKM$length,digits = 0),"km", sep=" ")

Agrupar features

Porque senão ficava muito lento

CicloviasAnos = Ciclovias %>% 
  group_by(DESIGNACAO,TIPOLOGIA,AnoT,ANO) %>% summarise() %>% ungroup()

CicloviasAnos$length = st_length(CicloviasAnos) %>% units::set_units(km)
sum(CicloviasAnos$length[CicloviasAnos$AnoT==2025]) #extensão da rede actual

Guardar ficheiros

Na pasta da app

saveRDS(CicloviasAnos, "CicloviasAnos/CicloviasAnos.Rds")
saveRDS(CicloviasKM, "CicloviasAnos/CicloviasKM.Rds")
st_write(Ciclovias |> select(-id), "data/Ciclovias_dez2025_CORRECT.gpkg", delete_dsn = TRUE)
st_write(Ciclovias, "data/Ciclovias_dez2025_CORRECT_id.gpkg", delete_dsn = TRUE)
saveRDS(Ciclovias, "data/Ciclovias_bk25.Rds")
# Exportar rede separada por anos
for (i in unique(Ciclovias$AnoT)){
  CicloviasAno = Ciclovias %>% filter(AnoT == i)
  st_write(CicloviasAno, paste0("data/Ciclovias por ano/Ciclovias_",i,".gpkg"), delete_dsn = TRUE)
}
knitr::opts_chunk$set(echo = TRUE)
library(tidyverse)
library(sf)
library(animation)

Importar os dados

Importar shapefile de Lisboa

#Limites de Lisboa
LisboaLimite = st_read("data/Lisboa_limite.gpkg")
LisboaLimite = LisboaLimite[,c(3,5)] %>% st_transform(LisboaLimite,  crs = 4326)
attr(LisboaLimite, "sf_column") = "geometry"
colnames(LisboaLimite)[colnames(LisboaLimite)=="geom"] <- "geometry"
# LisboaLimite2 = st_read("data/LisboaLimite.shp")
# st_write(LisboaLimite2, "data/LisboaLimite.shp", append = F)

Importar dados das ciclovias já processados

CICLOVIAS = readRDS("CicloviasAnos/CicloviasAnos.Rds")

Processar os dados

criar elementos vazios nos anos em que nao aconteceu nada

vazios <-data.frame(DESIGNACAO = as.character(NA),
                   TIPOLOGIA = as.character(NA),
                   AnoT = as.integer(c(2002,2004,2006,2007,2015)))
vazios$ANO <-vazios$AnoT
vazios$geom<-st_sfc(st_multilinestring())
vazios<-st_sf(vazios, crs=4326)
vazios$length = units::set_units(0, km)

CICLOVIASgif = rbind(CICLOVIAS, vazios)

Tornar os dados mais leves

CICLOVIASredux = CICLOVIAS %>% filter(TIPOLOGIA!="Percurso Ciclo-pedonal") %>%  group_by(TIPOLOGIA, AnoT) %>% summarise() 
CICLOVIASgif = CICLOVIASgif %>% filter(TIPOLOGIA!="Percurso Ciclo-pedonal") %>% group_by(TIPOLOGIA, ANO) %>% summarise()
CicloviasKMredux = CicloviasKM %>% filter(TIPOLOGIA!="Percurso Ciclo-pedonal") %>%  group_by(AnoT) %>% summarise(comprimento=sum(length))

CicloviasKMredux$Kms <- paste(round(CicloviasKMredux$comprimento,digits = 0),"km", sep=" ")

Criar as imagens

Definir o estilo dos mapas

# Defenir estilo de mapa
mapTheme <- function(base_size = 12) {
  theme(
    text = element_text( color = "black"),
    plot.title = element_text(size = 18,colour = "black"),
    plot.subtitle=element_text(face="italic"),
    plot.caption=element_text(hjust=0),
    axis.ticks = element_blank(),
    # panel.background = element_blank(), #transparente
    panel.background = element_rect(fill = "white"),
    #panel.grid.major = element_line("grey80", size = 0.1),
    panel.grid.major = element_line(color = "transparent"),
    strip.text = element_text(size=14,face = "bold"),
    axis.title = element_blank(),
    axis.text = element_blank(),
    axis.title.x = element_blank(),
    axis.title.y = element_blank(),
    panel.grid.minor = element_blank(),
    strip.background = element_rect(fill = "grey80", color = "white"),
    plot.background = element_blank(),
    legend.background = element_blank(),
    legend.title = element_text(colour = "black", face = "italic"),
    legend.text = element_text(colour = "black", face = "italic"))
}

Função para gravar uma imagem para cada ano

#preparar a função
listaAnos = seq(1:25)+2000
RedeCiclavelLxkm <- function(Year){
  slideano =  ggplot()+
    mapTheme()+
    #mapa base
    geom_sf(LisboaLimite, mapping = aes(), color = NA) +
    #rede existente no ano anterior
    geom_sf(data=subset(CICLOVIASredux,TIPOLOGIA=="Nao dedicada" & AnoT==Year),
          aes(fill =AnoT),color="grey80",size=1, show.legend=F) +
    geom_sf(data=subset(CICLOVIASredux,TIPOLOGIA=="Ciclovia dedicada" & AnoT==Year),
          aes(fill =AnoT),color="grey65",size=0.9, show.legend=F) +
    #novas ciclovias naquele ano
    geom_sf(data=subset(CICLOVIASgif,TIPOLOGIA=="Nao dedicada" & ANO==Year),aes(),
          color="#AFD4A0",size=1.1,show.legend=F) + #lty=88 ou 11 para tracejado
    geom_sf(data=subset(CICLOVIASgif,TIPOLOGIA=="Ciclovia dedicada" & ANO==Year),aes(),
          color="#1A7832",size=1.1,show.legend=F) +
    #aplicar o estilo com o ano em cima
    facet_wrap(~AnoT, nrow=1)+
    #adicionar o contador de km
    geom_text(data=subset(CicloviasKMredux,AnoT==Year),
            aes(x=-9.1,y=38.692,label=Kms), size=6,inherit.aes=FALSE)
  
    #gravar cada imagem
    ggsave(slideano, filename=paste0("GIF/2025/",Year,"km.png"),
         units="cm", width=18, height=18, dpi=300)
}
    

Correr a função

Para guardar cada imagem em separado

 listaAnos %>% map_df(RedeCiclavelLxkm)
# dá um erro mas funciona

Duplicar o último frame para ficar parado mais tempo no final.

Gravar como gif

convert -delay 60 -loop 0 -resize 700x700 GIF/2025/*.png GIF/RedeCiclavelLisboa2025.gif

Repositório de código aberto



Contribui para melhorar este site.
Se detectares erros indica aqui :)