如果伦敦地铁图是数据科学家画的……

简介:

我们每天乘坐的地铁是一个恢弘的艺术作品。

抛开路线、站点的规划不说,地铁的线路图本身就蕴藏了极其精妙的设计。

比如说伦敦地铁图。

伦敦的地铁路线图图可谓是地铁路线图的鼻祖。多年来,它形成的配色与排版方案,造就了它独特的外观和风格,但最令人惊叹的,还是其神来之笔的设计思路。

拥有13条路线,300多个站点,伦敦地铁的结果复杂至极。一些站点甚至连接了3到4条路线。

怎样才能有效地可视化这个网络?

20世纪初的设计大师Harry Beck交出了一份堪称完美的答卷。今天,一位数据科学家Keith McNulty也想来重新挑战一下这个难题。

这场跨越时空的pk究竟谁更胜一筹呢?赶紧搬来小板凳!

选手A:20世纪天才设计师Harry Beck

20世纪初期,伦敦在过去的半个多世纪内完成了很多雄心勃勃的地下和地面铁路项目,建成了一系列相互连接的复杂路线。

当年,伦敦地铁地图的设计者Harry Beck惊奇地发现,人们乘坐地铁时,他们并不在意自己所在的地理位置——他们真正关心的是乘坐多少站以及在哪里需要换乘。

意识到这点,Beck设计了今日地铁图的初稿,以一种尽可能简单的方法将所有线路绘制成直线,清楚显示线路互相连接的位置。

但Beck也知道,线路的地理方向是也不能在设计中被完全忽略,否则人们无法辨认东南西北——在看地图时,人们需要基本的方向感。

所以,在许多方面,Beck的地图富有设计感又兼顾准确性。

于是,他就创作出了下面这幅地铁路线图

c36d2115e8a77cab69d9893c4cdd74ae36d6d22b

请一秒钟记住这张图!

先不急着给出评价,接下来让我们来看看当代选手的作品。

选手B:21世纪数据科学家Keith McNulty

Keith给出了两种方案,分别遵从两种极端的设计原则。

1.完全忽略地理位置:使用“力导向图”决定站点的位置,与实际地理位置信息不相关。

2.完全遵从地理位置:类似于原始早期的Beck地铁图,使用空间坐标将网络叠在伦敦地铁上。

首先,我们需要找一个能够呈现伦敦地铁网络的数据源,包括站点和线路信息。

好消息是,这样的数据集已经在网上公开啦。这份数据甚至包含了地图线路的十六进制颜色编码。顺便说一下,伦敦交通局(Transport for London)发布过一个设计风格指南。

数据集:

https://github.com/nicola/tubemaps/tree/master/datasets

1、完全无地理信息的地铁图方案

现在,我们需要一个能够生成力导向图,并能够轻松进行可视化的算法。

R中 networkD3的forceNetwork()函数就是不二的选择 。

鉴于已有的数据和networkD3函数易于使用,这里不需要写太多复杂的代码。我们先加载库和三个调整过的原始文件。

 

# load libraries
library(networkD3)
library(dplyr)
# load data
stations <- read.csv( "stations.csv" )
connections <- read.csv( "connections.csv" )
lines <- read.csv( "lines.csv" )

stations 数据框(dataframe)只是一个列表,包含站点名称、每个站的ID号码以及站点的空间坐标(因为我们现在不考虑地理位置,所以暂时不需要该信息)。地铁图总共有302个站点。

lines数据框是包含整个网络13条线路的列表,附带线路的ID号码、线路名称和官方颜色。

connections 数据框表示所有线路任意两个站点之间的连接和连接线路的号码。这里共计有406个连接。

首先,让我们将网络的边变成官方地铁图的配色,并且根据节点所处的线路给节点(即站点)上色。当节点属于多条线路时,我们可以选择ID号码最小的线路为该节点的颜色。这意味着我们需要在stations 和connections 数据框中增加几列,用来获取站点的颜色和连接的颜色。

 

# bring in line colour into connections dataframe for edge colours

connections <- merge(connections, lines)

connections <- connections[ ,c( "station1" , "station2" , "line" , "colour" )]

# define a colour for each station using min of line ID

connections_unique_lines1 <- connections %>% dplyr::group_by(station1) %>%

dplyr::summarise(line = min(line))

colnames(connections_unique_lines1) <- c( "station" , "line" )

connections_unique_lines2 <- connections %>% dplyr::group_by(station2) %>%

dplyr::summarise(line = min(line))

colnames(connections_unique_lines2) <- c( "station" , "line" )

connections_unique_lines3 <- rbind(connections_unique_lines1, connections_unique_lines2)

connections_unique_lines <- connections_unique_lines3 %>% dplyr::group_by(station) %>%

dplyr::summarise(line = min(line))

# merge line IDs into stations dataframe

stations <- dplyr::left_join(stations, connections_unique_lines, by = c( "name" = "station" ))

# merge with lines dataframe to capture line_name

stations <- dplyr::left_join(stations, lines, by = "line" )

现在大部分工作已经完成。我们只需要对站点的索引从零开始进行编号,以符合的 D3.js格式要求:

 

# create indices for each name to fit forceNetwork data format

connections$source.index <- match(connections$station1, stations$name) - 1

connections$target.index <- match(connections$station2, stations$name) – 1

现在,我们有了绘制网络的所有东西。我们将使用networkD3包中的forceNetwork() 函数。

connections数据框包含了我们所需要的线路,而stations 数据框包含了节点的详细信息。我们使用stations数据框中的line_name 列对站点分组,以便对节点进行颜色编码;我们使用 connections 数据框中的 colour 列对线路进行颜色编码(根据线路的官方颜色)。

我们还需要定义与线路匹配的节点颜色,以及与伦敦地铁图相近的字体。我用的是Gill Sans,虽然它是非官方字体,但是非常接近(Eric Gill实际上为设计了原始地铁图字体的Edward Johnson工作)。

此处是生成网络的代码。

 

networkD3::forceNetwork(Links = connections, Nodes = stations,
Source = "source.index" ,
Target = "target.index" ,
NodeID = "name" ,
Group = "line_name" ,
colourScale = JS( 'd3.scaleOrdinal().domain(["Bakerloo",
"Central",
"Circle",
"District",
"East London",
"Hammersmith & City",
"Jubilee",
"Metropolitan",
"Northern",
"Piccadilly",
"Victoria",
"Waterloo & City", "Docklands"]).range(["#AE6017",
"#FF0000",
"#FFE02B",
"#00A166",
"#FBAE34",
"#F491A8",
"#949699",
"#91005A",
"#000000",
"#094FA3",
"#0A9CDA",
"#88D0C4",
"#00A77E"])' ),
linkColour = as.character(connections$colour),
charge = -30 ,
linkDistance = 25 ,
opacity = 1 ,
zoom = T,
fontSize = 12 ,
fontFamily = "Gill Sans Nova" ,
legend = TRUE)

最后的结果就是这样啦

90a4d2a1433e32ccf18273a770c49348f9ef618f

动态演示可以在这儿查看:

185de9d8866993b721f0e4e5b926d3f9ae187dbd

http://rpubs.com/keithmcnulty/tubemap

在绘制这张图时,我们完全不考虑地铁图的地理位置意义,将Beck的设计原则发挥到极致,并借助数据科学方法以最美观的方式将地铁图可视化。

如果你熟悉伦敦的区域分布,你会发现很多奇奇怪怪的事情。比如,现在位于伦敦南部的是艾坪镇(Epping)而非埃塞克斯(Essex)了。这对用户来说是非常糟糕的。

2、地理位置完全精确的地铁图方案

让我们看看另一个极端:完全遵从地理位置。

我们将主要使用ggplot2,当然这里还需要一些其他的库。

 

# load libraries
library(dplyr)
library(ggplot2)
library(sp)
library(rgdal)
# load data
stations <- read.csv( "stations.csv" )
connections <- read.csv( "connections.csv" )
lines <- read.csv( "lines.csv" )

为了完全遵从地理位置,我们可以将这些站点直接绘制在一张伦敦地图的相应位置。

在这里我们可以获得一份包含行政区边界的伦敦地铁图文件。

链接:

https://data.london.gov.uk/dataset/statistical-gis-boundary-files-london

首先,将其解压缩到一个名为london-map-data的文件夹中。然后,将数据转换成 ggplot2 可以使用的格式。

 

# import London borough GIS data
london <- rgdal::readOGR(file.path( "london-map-data" ))
sp::proj4string(london) <- sp::CRS( "+init=epsg:27700" )
london. map <- sp::spTransform(london, sp::CRS("+init=epsg:4326"))

有了正确格式的伦敦地图数据,我们便可使用ggplot2绘图。

 

# plot London boundaries

map1 <- ggplot(london. map ) +

geom_polygon(aes(x = long , y = lat, group = group), fill = "white" , colour = "black" )

map1 <- map1 + labs (x = "Longitude" , y = "Latitude" , title = "London Tube Routes" )

在这张简单的地图上,我们会画上地铁线路和站点:

07d195c10f9d1d47b364e232ba6909e6ed59cef4

因为stations 数据框有每个站点的空间坐标信息,画站点就十分方便。要绘制线路,我们需要将每个站点的空间坐标与 connections数据框相匹配。

 

# get spatial co-ordinates for each station pair in network
connections <- connections %>%
dplyr::inner_join(stations, by = c( 'station1' = 'name' )) %>%
dplyr::rename(x = longitude, y = latitude) %>%
dplyr::inner_join(stations, by = c( 'station2' = 'name' )) %>%
dplyr::rename(xend = longitude, yend = latitude)
connections <- merge(connections, lines)

由于ggplot2的调色板缺少部分十六进制的颜色,我们还需要人工选取与官方配色最接近的线路颜色。

 

# define line colours

linecolours <- c( "brown" , "yellow" , "pink" , "grey" , "lightblue" , "red" , "darkgreen" , "orange" , "maroon" , "black" , "darkblue" , "lightgreen" , "#00A77E" )

names(linecolours) <- lines$line_name

万事俱备,我们只需要在伦敦地图上绘制站点和线路即可——为求真实,这里我们仍旧使用Erci Gill的字体。

 

# plot network on London map
map1 +
geom_point(data = stations, aes(x = longitude, y = latitude)) +
geom_curve(aes(x = x, y = y, xend = xend, yend = yend,
color = line_name),
data = connections, curvature = 0.33 , size = 1 ) +
scale_color_manual(values = linecolours, name = "Line" ) +
theme(text = element_text(family= "Gill Sans Nova" ))

更清楚的地铁图:

http://rpubs.com/keithmcnulty/geotubemap

db3907913c69340a6c93b7dbf155c5227b1614c0

就是这样!

这张路线图虽然完全遵从了地理位置信息,但位处市中心的几个关键站点却挤到了一起,难以分辨,反而是位于郊区的站点得到了更充分的展示。

让我们最后再回过头看看Harry Beck的作品。

dbb3d5f352dda6b508ca288b4c1c934d05721eae

这张地铁图既保证了站点信息的清晰可见,又极大程度地还原了站点的相对地理位置。

更厉害的是,合理的信息分布让这一切都能被很好地呈现在一张小纸片上。

Harry的作品也被称为“世上最易识别和最有影响力的交通地图”。在此之后,几乎所有城市的地铁线路图设计方案都遵从了Harry当年的原则。

在折腾了这一通之后,这位数据家Keith McNulty也表示,他输得心服口服了。

“没有什么能替代人类聪明的设计——是的,什么都不行!” Keith McNulty发出了这样的感叹。


原文发布时间为:2018-09-9

本文来自云栖社区合作伙伴“大数据文摘”,了解相关信息可以关注“大数据文摘”。

相关文章
|
9月前
|
开发框架 API 决策智能
ModelScope-Agent框架再升级!新增一键配置多人聊天,配套开源多智能体数据集和训练
ModelScope-Agent是魔搭社区推出的适配开源大语言模型(LLM)的AI Agent(智能体)开发框架,借助ModelScope-Agent,所有开发者都可基于开源 LLM 搭建属于自己的智能体应用。在最新升级完Assistant API和Tool APIs之后,我们又迎来了多智能体聊天室的升级,通过几分钟快速配置即可搭建一个全新的聊天室。
面向对象练习题笔记(1)
面向对象练习题笔记(1)
100 0
|
Java
Java 面向对象 习题1(基础篇)
1、编写Address类 2、定义Employee类 3、编写程序,统计字符串 4、设计Dog类 5、设计User类
174 0
|
3天前
|
人工智能 自然语言处理 Shell
深度评测 | 仅用3分钟,百炼调用满血版 Deepseek-r1 API,百万Token免费用,简直不要太爽。
仅用3分钟,百炼调用满血版Deepseek-r1 API,享受百万免费Token。阿里云提供零门槛、快速部署的解决方案,支持云控制台和Cloud Shell两种方式,操作简便。Deepseek-r1满血版在推理能力上表现出色,尤其擅长数学、代码和自然语言处理任务,使用过程中无卡顿,体验丝滑。结合Chatbox工具,用户可轻松掌控模型,提升工作效率。阿里云大模型服务平台百炼不仅速度快,还确保数据安全,值得信赖。
157353 24
深度评测 | 仅用3分钟,百炼调用满血版 Deepseek-r1 API,百万Token免费用,简直不要太爽。
|
5天前
|
人工智能 API 网络安全
用DeepSeek,就在阿里云!四种方式助您快速使用 DeepSeek-R1 满血版!更有内部实战指导!
DeepSeek自发布以来,凭借卓越的技术性能和开源策略迅速吸引了全球关注。DeepSeek-R1作为系列中的佼佼者,在多个基准测试中超越现有顶尖模型,展现了强大的推理能力。然而,由于其爆火及受到黑客攻击,官网使用受限,影响用户体验。为解决这一问题,阿里云提供了多种解决方案。
16982 37
|
13天前
|
机器学习/深度学习 人工智能 自然语言处理
PAI Model Gallery 支持云上一键部署 DeepSeek-V3、DeepSeek-R1 系列模型
DeepSeek 系列模型以其卓越性能在全球范围内备受瞩目,多次评测中表现优异,性能接近甚至超越国际顶尖闭源模型(如OpenAI的GPT-4、Claude-3.5-Sonnet等)。企业用户和开发者可使用 PAI 平台一键部署 DeepSeek 系列模型,实现 DeepSeek 系列模型与现有业务的高效融合。
|
5天前
|
并行计算 PyTorch 算法框架/工具
本地部署DeepSeek模型
要在本地部署DeepSeek模型,需准备Linux(推荐Ubuntu 20.04+)或兼容的Windows/macOS环境,配备NVIDIA GPU(建议RTX 3060+)。安装Python 3.8+、PyTorch/TensorFlow等依赖,并通过官方渠道下载模型文件。配置模型后,编写推理脚本进行测试,可选使用FastAPI服务化部署或Docker容器化。注意资源监控和许可协议。
1310 8
|
13天前
|
人工智能 搜索推荐 Docker
手把手教你使用 Ollama 和 LobeChat 快速本地部署 DeepSeek R1 模型,创建个性化 AI 助手
DeepSeek R1 + LobeChat + Ollama:快速本地部署模型,创建个性化 AI 助手
3416 117
手把手教你使用 Ollama 和 LobeChat 快速本地部署 DeepSeek R1 模型,创建个性化 AI 助手
|
8天前
|
人工智能 自然语言处理 API
DeepSeek全尺寸模型上线阿里云百炼!
阿里云百炼平台近日上线了DeepSeek-V3、DeepSeek-R1及其蒸馏版本等六款全尺寸AI模型,参数量达671B,提供高达100万免费tokens。这些模型在数学、代码、自然语言推理等任务上表现出色,支持灵活调用和经济高效的解决方案,助力开发者和企业加速创新与数字化转型。示例代码展示了如何通过API使用DeepSeek-R1模型进行推理,用户可轻松获取思考过程和最终答案。

热门文章

最新文章