cd /news/developer-tools/proposta-workflow-md · home topics developer-tools article
[ARTICLE · art-10026] src=gist.github.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

PROPOSTA_WORKFLOW.md

The article proposes a workflow to streamline the creation of Mapbox GL JS style JSONs for a frontend application. Currently, the process involves manual styling in Mapbox Studio, which is a bottleneck; the solution is to generate the style JSON directly in R using functions for continuous, categorical, and step-based data, and optionally automate tileset uploads via the Mapbox Uploads API. This eliminates the need for manual styling in Mapbox Studio, with the final deliverable being a style JSON, tileset ID, and source layer name for the developer.

read3 min views19 publishedMar 18, 2026

Atualmente, o fluxo do Vinicius é:

  • Importar shapes e fazer limpeza no R
  • Exportar para geojson/mbtiles
  • Upload manual no Mapbox Studio
  • Estilização manual no Mapbox Studio (cores, breaks, etc.)
  • Copiar o JSON de estilo e colar no código O gargalo está na etapa 4 — a estilização manual no Mapbox Studio. O frontend espera um JSON de estilo no formato Mapbox GL JS expressions. Esse JSON pode ser gerado diretamente no R, sem precisar abrir o Mapbox Studio para estilizar. O Mapbox Studio passaria a ser usado apenas para upload do tileset (ou nem isso, se usar a API de uploads). R: limpeza dos dados R: definir cores, breaks, tipo de layer → gerar JSON de estilo R ou Mapbox Studio: upload do tileset Entregar ao dev: JSON de estilo + tileset ID + source layer name Dev: colar no código (layer-styles.ts + city-layers.ts) O frontend precisa de um objeto JSON com esta estrutura:
{
"id": "nome-do-layer",
"type": "fill",
"source": "composite",
"source-layer": "nome_do_source_layer",
"paint": {
"fill-color": [

"interpolate",

["linear"],
["get", "nome_da_propriedade"],

500, "#fee5d9", 1000, "#fcbba1", 1500, "#fc9272", 2100, "#fb6a4a", 2500, "#ef3b2c", 3000, "#cb181d", 3914, "#99000d"

],
"fill-outline-color": "#000000"
},
"layout": { "visibility": "none" },
"slot": ""
}

As variações possíveis de paint são:

Para dados numéricos contínuos (ex: densidade populacional):
library(jsonlite)
library(classInt)

valores <- seu_shapefile$Densidade_Populacional breaks <- classIntervals(valores, n = 6, style = "jenks")$brks cores <- c("#e5f5f9", "#99d8c9", "#66c2a4", "#41ae76", "#238b45", "#00441b")

gerar_interpolate <- function(propriedade, breaks, cores) {
stops <- as.list(interleave(breaks, cores))
lista <- list(

"interpolate",

list("linear"),
list("get", propriedade)
)
lista <- c(lista, stops)
return(lista)
}
interleave <- function(a, b) {
n <- min(length(a), length(b))
resultado <- vector("list", 2 * n)
resultado[seq(1, 2 * n, 2)] <- as.list(a[1:n])
resultado[seq(2, 2 * n, 2)] <- as.list(b[1:n])
return(resultado)
}
estilo <- list(
id = "densidade-populacional-setor",
type = "fill",

source = "composite", source-layer = "densidade_populacional_setor",

paint = list(
`fill-color` = gerar_interpolate("Densidade.Populacional", breaks, cores),
`fill-outline-color` = "#000000"
),
layout = list(visibility = "none"),

slot = ""

)
cat(toJSON(estilo, auto_unbox = TRUE, pretty = TRUE))
write(toJSON(estilo, auto_unbox = TRUE, pretty = TRUE), "estilo_densidade.json")
Para dados categóricos (ex: tipo de tarifa):
gerar_match <- function(propriedade, categorias, cores, cor_fallback = "#000000") {
lista <- list(

"match",

list("get", propriedade)
)
for (i in seq_along(categorias)) {
lista <- c(lista, list(list(categorias[i])), list(cores[i]))
}
lista <- c(lista, list(cor_fallback))
return(lista)
}
categorias <- c("Integral", "Parcial", "Revogado")
cores <- c("#2166ac", "#80cdc1", "#b2182b")
estilo <- list(
id = "tarifa-zero",
type = "circle",

source = "composite", source-layer = "tarifa_zero_municipios",

paint = list(
`circle-color` = gerar_match("Tipo de Tarifa Zero", categorias, cores),
`circle-radius` = 8
)
)
cat(toJSON(estilo, auto_unbox = TRUE, pretty = TRUE))

Para dados com faixas definidas:

gerar_step <- function(propriedade, breaks, cores) {
lista <- list(

"step", list("get", propriedade), cores[1] # cor para valores abaixo do primeiro break

)
for (i in 2:length(breaks)) {
lista <- c(lista, list(breaks[i]), list(cores[i]))
}
return(lista)
}

Para eliminar também o upload manual no Mapbox Studio, é possível usar a API do Mapbox diretamente no R:

library(httr)
mapbox_token <- Sys.getenv("MAPBOX_SECRET_TOKEN")
username <- "observatorio-nacional"
creds <- GET(

paste0("https://api.mapbox.com/uploads/v1/", username, "/credentials"),

query = list(access_token = mapbox_token)
)
creds_body <- content(creds)

Ou usar o pacote mapboxapi : library(mapboxapi) upload_tiles( input = "dados/meu_shapefile.geojson", username = "observatorio-nacional", tileset_id = "meu_novo_tileset", tileset_name = "Meu Novo Tileset", multipart = TRUE ) Depois de rodar o script R, o Vinicius entrega 3 coisas: Além disso, os metadados para a UI: O Mapbox Studio se torna opcional — útil apenas para preview visual, não mais como ferramenta de produção.

── more in #developer-tools 4 stories · sorted by recency
── more on @vinicius 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/proposta-workflow-md] indexed:0 read:3min 2026-03-18 ·