Xu Kuang http://xukuang.github.io/ 2017-10-04T12:24:56+00:00 kuang_xu@126.com 基于Emaps包的中国省市级地图 http://xukuang.github.io/blog/2017/10/map-of-each-province/ 2017-10-04T12:18:05+00:00 Xu Kuang http://xukuang.github.io/blog/2017/10/map-of-each-province 省级指标图
library(REmap)
head(chinaIphone)
chinaIphone
remapC(chinaIphone)

市级指标图

mapNames("河南")
set.seed(123)
henan = data.frame(country = mapNames("河南"), value = sample(17))
remapC(henan, maptype = "河南",color = "skyblue")

观测点图

park = read.csv('park_result.csv')
geodata = data.frame(park$lon, park$lat, park$park)

pointData = data.frame(park$park, color = 'red')


remapC(henan, maptype = "河南",color = "skyblue",
       markPointData = pointData,
       markPointTheme = markPointControl(symbol = "pin",
                                         symbolSize = 5,
                                         effect = F),
       geoData = geodata)

- - - - - -

]]>
地图数据shapfile文件在R中的读取.md http://xukuang.github.io/blog/2017/10/shapefile-in-r/ 2017-10-04T08:18:02+00:00 Xu Kuang http://xukuang.github.io/blog/2017/10/shapefile-in-r Shapefile文件概述

Shapefile文件是美国环境系统研究所ESRI所研制的GIS文件系统格式文件,用来储存基于向量的地理数据(如点、线、面)。Shapefile文件指是由多个文件组成的。其中,要组成一个Shapefile,有三个文件是必不可少的,它们分别是”.shp”, “.shx”与 “.dbf”文件。表示同一数据的一组文件其文件名前缀应该相同。例如,存储一个关于湖的几何与属性数据,就必须有lake.shp,lake.shx与lake.dbf三个文件。而其中“真正”的Shapefile的后缀为shp,然而仅有这个文件数据是不完整的,必须要把其他两个附带上才能构成一组完整的地理数据。除了这三个必须的文件以外,还有八个可选的文件,使用它们可以增强空间数据的表达能力。 必须的文件:

  • .shp — 图形格式,用于保存元素的几何实体。
  • .shx — 图形索引格式。几何体位置索引,记录每一个几何体在shp文件之中的位置,能够加快向前或向后搜索一个几何体的效率。
  • .dbf — 属性数据格式,以dBase IV的数据表格式存储每个几何形状的属性数据。

在每个.shp, .shx与.dbf文件之中,图形在每个文件的排序是一致的。也就是说,.shp的第一条记录与.shx及.dbf之中的第一条记录相对应,如此类推。此外,在.shp与.shx之中,有许多字段的字节序是不一样的。因此用户在编写读取这些文件格式的程序时,必须十分小心地处理不同文件的不同字节序。

Shapefile文件读取

R有多个包可以读取shapfile文件并作地图,这里以中国各省及直辖市地图bou2_4p为例,介绍几种用来读取shapefile文件的方法。其中前两种方法要依赖sp包,它定义了一个spatial类型的集合,事实上是R里边标准的空间数据格式。

方法一:maptools包

maptools包提供了多个函数用来对R当中的空间对象进行读、写、转换或者其他的处理。用来读shapefile的通用函数是readShapeSpatial,这个函数可以自动识别shapefile(或其他R对象)中是否包含点、线或面,然后对特殊的类型采用专门的函数把数据读入。这些专门的函数包括readShapePoints,readShapeLines,readShapePoly等,用来分别读点、线、面。这样做的好处是当你搞错类型时,它会报错。和下边rgdal包的对应方法不同的是,maptools的函数并不读入投影信息,而是留给你手工处理(如果需要的话)。

library(maptools) 
china_map<-readShapePoly("bou2_4p.shp") 
plot(china_map, axes=F, border="gray") 


class(china_map) 

	[1] "SpatialPolygonsDataFrame" 

readShapePoly()函数虽然读取的是bou2_4p.shp文件,但在默认情况下会把dbf文件的信息也放到变量china_map之中,因此.shx 和 .dbf文件也必须在同一个文件目录下才能读取成功。

这时一张完整的中国地图就已经画好了。但是在实际使用的过程中,往往需要根据情况对地图中的某些省份着以特定的颜色,这时就可以通过调节plot命令中的col参数来予以实现。然而为了清楚地说明这部分的内容,需要插播一段R绘制地图的原理。

====================== 传说中的分割线 =====================

在绘制地图时,每一个省市自治区或者岛屿都是用一个多边形来表示的。之前的 GIS数据,其实就是提供了每一个行政区其多边形逐点的坐标,然后R软件通过顺次连接这些坐标,就绘制出了一个多边形区域。在上面的数据中,一共包含了925个多边形的信息,之所以有这么多是因为一些省份有很多小的附属岛屿。在这925个多边形中,每一个都对应一个唯一的ID,编号分别从1到925。

china_map@data

在R中输入china_map@data,会得到一个925行7列的数据框,这其实是bou2_4p.dbf这个文件中存储的信息。对于这个数据框,其行名就是每一个区域的ID编号,第一列和第二列分别是面积和周长,最后一列是该区域所属的行政区名,其它的列应该也是一些编号性质的变量,其中,ADCODE99是国家基础地理信息中心定义的区域代码,共有 6 位数字,由省、地市、县各两位代码组成。这个数据少了澳门特别行政区,这是这个数据中的一块瑕疵。第899行有一个NA,不知道它代表的是否就是澳门。

====================== 传说中的分割线 =====================

回到刚才的话题,plot命令中的col参数在本例中应该是一个长度为925的向量,其第i个分量的取值就代表了地图中第i个多边形的颜色。一个简单的尝试是运行下面这个命令看看效果:

plot(china_map,col = gray(924:0/924));

于是自然就产生了一个问题:如何获取某一个特定地区的ID,进而设置我们想要的颜色?事实上,可以通过查找相应的行政区对应的行名,就可以对col参数进行赋值了。

china_map@data

方法二:rgdal包

rgdal包提供了GDAL/OGR library(The Geospatial Data Abstraction Library)的接口。rgdal包里边的函数readOGR可以读包括shapefile在内的多种基于向量的数据格式。ogrInfo函数可以在不读全部数据集的情况下检索数据的细节,看一下数据的情况:

library(rgdal)

读数据:

china_map1<- readOGR(".", "bou2_4p") 
  # OGR data source with driver: ESRI Shapefile 
  # Source: ".", layer: "bou2_4p" 
  # with 925 features and 7 fields 
  # Feature type: wkbPolygon with 2 dimensions 

 plot(china_map1, axes=F, border="gray") 

 china_map1@data

方法三:PBSmapping包

PBSmapping包只能读不能写shapefile数据。这个包采用自定义的空间数据类型,因此不能利用许多基于sp包开发的R包。

library(PBSmapping)
china_map2 <- importShapefile("bou2_4p",readDBF=FALSE) 
str(china_map2)#看数据集的属性 
plotPolys(china_map2) 

方法四: shapefiles包

这个包是专门用来读写ESRIhapefile数据文件的。read.shapefile函数可以读入完整的shapefile文件(包括.shp, .shx和.dbf),但是,它读进来之后的数据格式是列表的列表,对于ggplot2作图还是麻烦的很。画图时需要先把数据格式进行转化。

library(shapefiles)
china_map3 <- read.shapefile("bou2_4p") 

shapefile文件的处理还是有一点麻烦的。对于非空间数据的研究应用人士来说,画个地图也不一定要这么大费周章。因为R还有好几个利用其他地图数据来源绘制地图的工具。 下一篇,介绍ggmap包。

- - - - - -

本篇几个包的文档:

shapefile: http://cran.r-project.org/web/packages/shapefiles/shapefiles.pdf

maptools: http://cran.r-project.org/web/packages/maptools/maptools.pdf

rgdal: http://cran.r-project.org/web/packages/rgdal/rgdal.pdf

PBSmapping: http://cran.r-project.org/web/packages/PBSmapping/PBSmapping.pdf

在网上找shapefile文件并不麻烦,世界各国的行政区划shapefile文件:http://gadm.org/

]]>
REmap的作用 http://xukuang.github.io/blog/2017/10/study-remap/ 2017-10-02T08:31:23+00:00 Xu Kuang http://xukuang.github.io/blog/2017/10/study-remap 获取经纬度
  • get_city_coord 获取一个城市的经纬度
  • get_geo_position 获取一个城市向量的经纬度
library(REmap)
city_vec = c("北京","Shanghai","广州")
get_city_coord("Shanghai")
	[1] 121.45950  31.21004
get_geo_position (city_vec)
              lon       lat     city
    1  121.459503 31.210037 Shanghai
    12 116.413554 39.911013     北京
    21 113.270793 23.135308     广州

分级统计图

remapC是用于创建分级统计图(Choropleth map)。.即根据子区域数值的多少进行深浅不同的颜色填充的地图形式。目前支持的地图为:‘china’ 中国省份地图,‘world’ 世界地图,各省市地图,如’广东’,’西藏’等。 函数的调用形式为:

remapC(data,
       maptype = ‘china’,
      color = c(‘#1e90ff’,’#f0ffff’),
      theme = get_theme("Bright"),
      title = "",
      subtitle = "",
      mindata = NA,
      maxdata = NA,
      # mark Line & point
      markLineData = NA,
      markPointData = NA,
      markLineTheme = markLineControl(),
      markPointTheme = markPointControl(),
      geoData = NA)

参数看起来很多,这里仅描述前几个参数,后面的markLine与markPoint是用于在绘制好的地图上添加标线和标点的,会在remapB中详细介绍。remapC中重要的参数有:

  • data:数据框,第一列为子区域名(比如全国地图的省名,省级地图的市名)。
  • color:传入单个颜色就使用从白色到该色的填充,多个颜色根据值大小计算填充颜色。
  • maptype:地图的格式,’china’代表中地图,’world’代表世界地图。
head(chinaIphone)
remapC(chinaIphone)
remapC(chinaIphone,
      color = 'orange')
## 颜色改为白色到橘红色
remapC(chinaIphone,
      color = c('orange','red'))

此外,使用mapType参数可以改变地图的类型,绘制子地图或者世界地图。

世界地图

data = data.frame(country = mapNames("world"),
                   value = sample(178)+200)
head(data)
remapC(data,maptype = "world",color = 'skyblue')

子地图

mapNames()函数可以得到某个地图下的子图信息。

mapNames(‘西藏’)

data = data.frame(country = mapNames('西藏'),
                   value = sample(7)+200)
head(data)
remapC(data,maptype = '西藏',color = 'skyblue')

地图精细

remapC(chinaIphone,
        title = "remapC实例地图",
        theme = get_theme("none",backgroundColor = "#fff",
                          titleColor = "#1b1b1b",
                          pointShow = T),
        max = 2000)

底图的呈现

remapB是用于创建一个以百度地图为底图的recharts效果,有以下特点:

  1. 支持滚轮缩放,拖拽地图
  2. 详细的地图效果
  3. 可视化主要以标线与标点的形式做出

remapB的使用

函数的调用形式为:

remapB(center = c(104.114129,37.550339),
       zoom = 5,
       color = "Bright",
       title = "",
       subtitle = "",
       # mark Line & point
       markLineData = NA,
       markPointData = NA,
       markLineTheme = markLineControl(),
       markPointTheme = markPointControl(),
       geoData = NA)
  • center:地图的中心(经纬度坐标),可以从get_city_coord获得
  • zoom:地图缩放尺寸越小地图越大,(5代表国家级的地图,15代表市级的地图)
  • color:地图的颜色风格,默认颜色风格,除了12个内置颜色风格,可以使用“none”来自定义颜色。 background
library(devtools)
install_github('lchiffon/REmap')
library(REmap)

没有标点和标线的Bmap效果

remapB()
remapB(color = "Blue")
remapB(color = "pink")

remapB(get_city_coord("北京"),zoom = 12)

标线

markLine是Echarts中进行标线的工具。通过标线(直线,曲线),可以完成很多有意思的可视化。

  • markLineData 标线使用的数据,第一列为出发地,第二列为目的地
  • markLineTheme 控制标线颜色,形状等,由markLineControl来控制
  • geoData 标中各个点的经纬度坐标。如果没有,会使用BaiduAPI自动查找

markLine的这些参数需结合remapC或者remapB使用。

标线数据

markLineData 标线使用的数据,第一列为出发地,第二列为目的地

remapB(title = "Bmap迁徙图示例",
        color = "Blue",
    	markLineData = demoC)

标线风格

markLineTheme控制了标线的风格,使用markLineControl来调用。这里列出主要的参数:

markLineControl(symbolSize = c(2,4),
      smoothness = 0.2,
      effect = T,
      lineWidth = 1,
      lineType = ‘solid’,
      color = "Random") 
  • symbolSize:形状的大小,标线默认是一端无形状,一端箭头,如果不想要箭头可以使symbolSize = c(0,0)。
  • smoothness:曲线的弯曲度。取0标线会退化为直线。
  • effect:炫光特效,标线较多的时候建议关闭。
  • lineWidth:标线的宽度。
  • lineType:标线的样式: ’solid’实线,’dotted’点线, ’dashed’虚线。
  • color:颜色,默认为随机颜色,设置一个颜色会取为固定颜色。
remapB(title = "Remap:  百度迁徙模拟",
       color = "Blue",
       markLineData = demoC,
       markLineTheme = markLineControl(symbolSize = c(0,0),
                                       lineWidth = 10,
                                       lineType = ‘dashed’))

经纬度坐标

geoData 标中各个点的经纬度坐标。如果没有,会使用BaiduAPI自动查找。若会使用BaiduAPI查找不到,必须提供经纬度坐标。mapC和mapB中,都会有geoData这个变量,用以储存markLine和markPoint的地理位置信息。具体的格式与get_city_coord返回相同。第一列为lon,第二列为lat,第三列为地理名称。

get_geo_position(c("Beijing","Shanghai","Guangzhou"))

       lon      lat      city
1 116.4232 39.91528   Beijing
2 121.5221 31.30477  Shanghai
3 113.2684 23.12980 Guangzhou

标点

markLine是Echarts中进行标线的工具。通过标线(直线,曲线),可以完成很多有意思的可视化。 markPoint是Echarts中进行标点的工具。通过不同形状的点(箭头,星,圆或者自定义的图片)来完成点的标注。

  • markPointData 标点使用的数据,可以是一个向量,如果是数据框就仅使用第一列。
  • markPointTheme 控制标点颜色,形状等,由markPointControl来控制
  • geoData 标中各个点的经纬度坐标,如果没有,会使用BaiduAPI自动查找。

与markLine类似,markLine的这些参数需结合remapC或者remapB使用。

标点数据

markPointData 标点使用的数据,可以是一个向量,如果是数据框就仅使用第一列。

remapB(title = "Remap:  百度迁徙模拟",
       color = "Blue",
       markPointData = demoC[,2])

标点风格

markPointTheme控制了标点的风格,使用markPointControl来调用。这里列出主要的参数:

markPointControl(symbol = ‘emptyCircle’,
                  symbolSize = "Random",
                  effect = T,
                  effectType = ‘scale’,
                  color = "Random")
  • symbol。‘circle’,‘emptyCircle’圆,空心圆。‘rectangle’,‘emptyRectangle’,方块,空心方块。‘triangle’,‘emptyTriangle’,三角,空心三角。‘diamond’,‘emptyDiamond’,钻石,空心钻石。‘heart’心形,’droplet’,水滴。‘pin’,POI标注,’arrow’箭头, ’star’五角星。或者使用’image://http://….’来引用一个图片。
  • symbolSize:标点的大小。
  • effect:炫光特效,标线较多的时候建议关闭。
  • effectType:炫光特效的方式,’scale’放大,’bounce’跳动。
  • color:颜色,默认为随机颜色,设置一个颜色会取为固定颜色。

经纬度坐标

geoData 标中各个点的经纬度坐标。如果没有,会使用BaiduAPI自动查找。若会使用BaiduAPI查找不到,必须提供经纬度坐标。mapC和mapB中,都会有geoData这个变量,用以储存markLine和markPoint的地理位置信息。具体的格式与get_city_coord返回相同。第一列为lon,第二列为lat,第三列为地理名称。

绘制迁徙地图

绘制地图使用的是主函数remap。

remap(mapdata, title = "", subtitle = "",
      theme =get_theme("Dark"))
  • mapdata: 一个数据框对象,第一列为出发地点,第二列为到达地点。
  • title:标题。
  • subtitle:副标题。
  • theme:控制生成地图的颜色,具体将会在get_theme部分说明。
library(REmap)
set.seed(125)
origin = rep("北京",10)
destination = c("上海","广州","大连","南宁","南昌","拉萨","长春","包头","重庆","常州")
dat = data.frame(origin,destination)
out = remap(dat,title = "REmap实例数据",subtitle = "theme:Dark")
plot(out)

个性化地图

REmap中get_theme提供了地图中常用颜色的调整:

get_theme(theme = "Dark", lineColor = "Random",
  backgroundColor = "#1b1b1b", titleColor = "#fff",
  borderColor = "rgba(100,149,237,1)", regionColor = "#1b1b1b")
  • theme:默认颜色主题,除了12个内置颜色主题,可以使用“none”来自定义主题。
  • lineColor: 线条颜色,默认随机,也可以使用固定颜色。
  • backgroundColor: 背景颜色。
  • titleColor: 标题颜色。
  • borderColor:边界颜色(省与省之间的信息)。
  • regionColor: 区域颜色。
## 默认模板: Bright
## default theme:"Bright"
set.seed(125)
out = remap(dat,title = "REmap实例数据",subtitle = "theme:Bright",
            theme = get_theme("Bright"))
plot(out)
out = remap(dat,title = "REmap实例数据",subtitle = "theme:Bright",
            theme = get_theme("None",
                              lineColor = "orange",
                              backgroundColor = "#FFC1C1",
                              titleColor = "#1b1b1b",
                              regionColor = "#ADD8E6"))
plot(out)

- - - - - -

学习资料:

REmap使用手册1-5

]]>
JavaScript初步介绍 http://xukuang.github.io/blog/2017/02/javascript/ 2017-02-04T10:00:36+00:00 Xu Kuang http://xukuang.github.io/blog/2017/02/javascript if("12345678"==prompt("请输入密码")) { alert("正确"); } else { alert("错误"); location="http://blog.laphets.com"; #返回网站,请自定义 }

JavaScript一种脚本编程语言,用于决定如何动态改变HTML元素。

HTML文件使用JavaScript的方式

  • 在HTML中使用JavaScript
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body>
</body>
<!--插入JavaScript代码-->
<script type="text/javascript">
console.log('Hello Wold')
</script>

</html>
  • 引入外部JavaScript文件
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <!--引入外部JavaScript文件-->
    <style type="text/css">out.js</style>
</head>

<body>
</body>
</html>

常用内容

  • document.getElementById(“demo”)可返回对拥有指定 ID 的第一个对象的引用
  • var carName = “Volvo”创建一个变量,变量名为 carName, 值为 “Volvo” :
  • HTMLElementObject.innerHTML=text 设置或返回开始标签和结束标签之间的 HTML。
  • console.log打印信息
  • 运算符,条件和循环语句
  • 用两个斜杠表示注释
]]>
R中的颜色设置 http://xukuang.github.io/blog/2016/12/r-color/ 2016-12-18T06:59:36+00:00 Xu Kuang http://xukuang.github.io/blog/2016/12/r-color 本文主要讲述R中的固定颜色选择函数、颜色生成函数、特定颜色主题调色板和RColorBrewer包的使用。

固定颜色函数

固定颜色选择函数也就是R提供的它自带固定种类的颜色,主要是函数包括colors()以及palette()。

colors()函数

通过colors()函数可以查看颜色的名字,默认有657种颜色。每种颜色对应的RGB值和16进制值可以在这里查看。这些颜色的调用有三种方法:

  • 使用colors()函数返回的结果
  • 颜色名字,即上面所显示的那么多种颜色
  • 颜色编码(用6位16进制的字符串表示,前面加“#”号表示)
colors()
x <- seq(0, 2*pi, len = 51)
plot(x, sin(x), type = "o", pch = 21, col = colors()[552])

plot(x, sin(x), type = "o", pch = 21, col = 'red')

plot(x, sin(x), type = "o", pch = 21, col = '#FF0000')

palette()函数

palette()函数可以查看调色板中的颜色,其中第一种颜色是黑色,第二种颜色是红色。这个调色板共有8种颜色,当使用颜色数大于8时,会从头开始。

palette()
	# [1] "black"   "red"     "green3"  "blue"    "cyan"    "magenta" "yellow" 
	# [8] "gray"

当然,调色板当然是可以改变的。

palette(c("red","green","blue","yellow","cyan"))

此时,第二位可就不是红色了。通过再次将palette设置为”default”,可以得到默认调色板。

palette("default")

调色板的好处在于,我们可以在R中使用一个整数来表示颜色,而这个整数对应的颜色就是调色板中相应位置的颜色,比如在某作图函数中调用参数col = 2表示取调色板中第2种颜色。若整数值超过了调色板颜色向量的长度,那么R会自动取该整数除以调色板颜色向量长度的余数。

颜色生成函数

R提供了一系列利用颜色生成原理(如RGB模型(红绿蓝三原色混合)、HSV色彩模型(色调、饱和度和纯度)、HCL色彩模型(色调、色度和亮度)和灰色生成模型等)构造的颜色。这里只介绍RGB模型和灰色生成模型对应的rgb()和gray()函数。

rgb()函数

rgb(red, green, blue, alpha, names = NULL, maxColorValue = 1)

其中前四个参数都取值于区间[0,maxColorValue],maxColorValue默认值为1,我们也可以设置为255。nmes参数用来指定生成颜色向量的名称。这里前三个参数不用过多解释,值越大就说明那种颜色的成分越高;可能alpha我们不太熟悉,它指的是颜色的透明度,取0表示完全透明,取最大值表示完全不透明(默认),透明度在统计图形中有着重要地 位,因为它具有一个非常有用的性质—透明度可以叠加,即:两个或多个带有透明色的图形元素重叠在一起时,重叠部分的透明度会变小;这在某些统计图形中可以找到很好的应用,例如当散点图中点的数目过多而导致大量的点相互重叠时,我们可以使用透明色来看清图中的深层规律,其中一个直接的规律就是二维密度,点重叠越密集,则颜色越深(由于透明度的的叠加),该处的密度值也越大。

gray()函数

gray()生成灰色系列;只有一个参数level,表示灰度水平,取值在0到1之间,其中0表示纯黑色,而1表示纯白色;level取一个向量则可以生成一系列灰色值。

特定颜色主题调色板

特定颜色主题调色板都用一系列渐变的颜色表现了特定的主题,例如彩虹颜色系列、白热化颜色系列、地形颜色系列等等。

rainow()

rainbow() 是彩虹的颜色(“红橙黄绿青蓝紫”)来产生一系列颜色。rainbow()的参数n设定产生颜色的数目(n是我们主要的参数),参数s表示过饱和度,和参数gamma表示纯度,参数gamma表示伽玛校正,参数start和end设定彩虹颜色的一个子集,生成的颜色将从这个子集中选取,这个子集选取的大致分界线为:红色(red)为0,黄色(yellow)为1/6,绿色(green)为2/6,青色(cyan)为3/6,蓝色(blue)为4/6,红紫色(magenta)为5/6。

heat.colors()

heat.colors() 从红色渐变到黄色再变到白色(以体现“高温”、“白热化”)。

terrain.colors()

terrain.colors() 从绿色渐变到黄色再到棕色最后到白色(这些颜色适合表示地理地形)。

topo.colors()

topo.colors() 从蓝色渐变到青色再到黄色最后到棕色。

cm.colors()

cm.colors() 从青色渐变到白色再到粉红色。

pie(rep(1, times = 1000), labels = "", col = rainbow(1000), border = rainbow(1000))

pie(rep(1, times = 1000), labels = "", col = heat.colors(1000), border = heat.colors(1000))

pie(rep(1, times = 1000), labels = "", col = terrain.colors(1000), border = terrain.colors(1000))

pie(rep(1, times = 1000), labels = "", col = topo.colors(1000), border = topo.colors(1000))

pie(rep(1, times = 1000), labels = "", col = cm.colors(1000), border = cm.colors(1000))

RColorBrewer包

RColorBrewer包中颜色板被划分为序列型(sequential)、离散型(diverging)、分类型(qualitative)。序列型颜色板适用于从低到高排序明显的数据,浅色数字小,深色数字大。离散型颜色板适合带“正、负”的,对极值和中间值比较注重的数据。分类型颜色板比较适合区分分类型的数据。这三种基本能满足统计作图需要的类型,颜色都比较协调。RColorBrewer包中实际用到的就只有brewer.pal()函数。用户只需要指定调色板名称,就可以用包中的brewer.pal()函数生成颜色。

序列型(sequential)

序列型(sequential)共18组颜色,每组分为9个渐变颜色展示。使用渐变色往往能让图形看起来更美观,避免单调的颜色在图形中显得突兀。实现代码如下:

display.brewer.all(type = "seq")

以上代码展示的序列型(sequential)配色方案中各组颜色的名称和样式。如果想使用YlOrRd组的第3~8种颜色,则可用如下代码来实现。

barplot(rep(1,6),col=brewer.pal(9, "YlOrRd")[3:8])

从上例可知,可以使用brewer.pal(9, “某组渐变颜色的名称>”)来获取该组渐变色的全部9种颜色。

离散型(diverging)

离散型(diverging)共9组颜色,每组分为11个渐变颜色展示。其实现代码如下:

display.brewer.all(type = "div")

上述代码展示的离散型(diverging)配色方案中各组颜色的名称和样式。如果想使用BrBG组的第3~8种颜色,则可用如下代码来实现。

barplot(rep(1,6),col=brewer.pal(11, "BrBG")[3:8])

和序列型(sequential)渐变色的使用不同,由于离散型中每组颜色分为11个渐变颜色,因此brewer.pal函数第一个参数不再是9,而是11,即应使用brewer.pal (11, “某组渐变颜色的名称”)来读取该组渐变的11种颜色。

分类型(qualitative)

分类型(qualitative)共8组颜色,每组渐变颜色数也不尽相同。其实现代码如下:

display.brewer.all(type = "qual")

上述语句展示的分类型(qualitative)配色方案中各组颜色的名称和样式。通过brewer.pal (n, “某组渐变颜色的名称”)语句可以读取该组内的n个渐变色(其中n是该组内渐变色的数目)。

- - - - - -

参考文章

1.谢益辉《统计图形》

2.R语言中的色彩和调色板

3.4.RColorBrewer颜色扩展包

]]>
使用R操作MySQL http://xukuang.github.io/blog/2016/12/r-mysql/ 2016-12-16T13:32:53+00:00 Xu Kuang http://xukuang.github.io/blog/2016/12/r-mysql 目的

使用R将豆瓣电影数据导入到MySql中。

平台

所有代码在windows7系统上运行。

数据

豆瓣电影数据,点击这里 从张宏伦的Github上下载。

实现

# 加载需要的R包
library(RMySQL)
library(data.table)

# 读取数据
movie = fread('data/douban_movie_clean.txt', sep = '^', encoding = 'UTF-8')


movie = data.frame(movie)
head(movie)

## 连接数据库
conn <- dbConnect(RMySQL::MySQL(), username="root", password= '123456', host="localhost", port=3306, dbname = 'study')

# 查看MySQL连接实例信息
summary(conn, verbose = TRUE)
# 查看数据库的表
dbListTables(conn)

# 建表并插入数据
dbWriteTable(conn,"movie", movie, overwrite = T)

# 设置数据库的连接信息
dbSendQuery(conn,'SET NAMES gbk')

# 读取数据库信息到R中
mysql=dbGetQuery(conn,"select * from movie")

## 关闭连接
dbDisconnect(conn)

利用R将数据写入到MySql中,与python不同,不需要提前在数据库中建立一个空表,就可以直接把数据作为一个数据表导入到数据库中。然而,这里也有一个前提,你必须要把要数据表要导入的数据库的排序规则设置为gbk_chinese_ci(当然这里指文件中含有中文)。导入数据前,需要对MySql数据库的排序规则特别设置,不知道是windows下的特有情况,还是所有系统下,都要提前设置。

此外,还要特别提醒,从外部向R读入豆瓣电影数据的时候,由于存在缺失值,在windows的R中read.csv不能自动跳过这一行会提示错误(好像mac和linux下的read.csv()函数能自动跳过有缺失值的行,真是坑人的windows),只能使用data.table包里的fread()函数(找到找个函数,还多亏张宏伦建的微信群里面的网友帮助)。

最后,还有一个问题,一直不太明白,就是这条语句dbSendQuery(conn,’SET NAMES gbk’)。从数据库中读取数据数据时,数据本身就是gbk格式,不知道为什么还要进行限制,貌似没有这条语句,R不能顺利读取MySql的数据。事实上,编码格式,一直困惑着我,尤其是windows下的编码格式。什么数据文件本省的编码格式,软件(R或者)本身的编码格式,windows的编码格式,一头雾水。还希望看到博客的朋友们指点迷津。

- - - - - -

参考文章

1.R批量处理txt文件并写入MySQL

2.RMySQL数据库编程指南

]]>
爬取豆瓣电影数据 http://xukuang.github.io/blog/2016/12/spider-douban/ 2016-12-16T12:42:53+00:00 Xu Kuang http://xukuang.github.io/blog/2016/12/spider-douban 目的

使用R爬取豆瓣电影数据。

平台

所有代码在windows7系统上运行。

实现

这里只是简单的在R中实现了张宏伦课程中爬取豆瓣电影的例子,具体的原理还要参考他的课程。

# 加载需要的R包
library(rvest)
library(rjson)
library(stringr)
library(dplyr)

# 读取数据
url = 'https://movie.douban.com/j/search_tags?type=movie'
web <- read_html(url,encoding="UTF-8")

# 找出电影的不同类型
tags <- web %>% html_nodes('p') %>% html_text() %>% fromJSON()
tag = tags$tags

basicurl<-"https://movie.douban.com/j/search_subjects?type=movie&tag="

# 爬取不同类型电影函数
WebSpider = function(m){
  i = 0
  # 存放每个类型电影的结果
  result = data.frame()
  while(1){
    #Sys.sleep(runif(1,1,2)) # 限制两次爬虫运行的时间
    url = str_c(basicurl,m,'&sort=recommend&page_limit=20&page_start=', i)
    
    web<-read_html(url,encoding="UTF-8")
    
    # 提取不同页的电影数据,并把数据格式由json转化list
    movies.inf = web %>% html_nodes("p") %>% html_text() %>% fromJSON()
    
    # 转化为数据格式为数据框
    temp = do.call("rbind",movies.inf$subjects)
    
    # 合并每个类型所有页的电影数据
    result = rbind(result, temp)
    if(is.null(temp)){
      print(i);break} else{
        i = i + 1} 
  }
  
  # 在数据中添加电影分类
  result$tags = m
  # 合并不同类型的电影数据
  return(result)
}

# 存放所有类型的电影
movies <- data.frame()

# 爬取所有类型的电影
for(j in 1:length(tag)){
  movies <- rbind(movies, WebSpider(tag[j]))}

# 转化列表中的每一项为字符型
movies.df = lapply(movies, as.character)

# 去除重复的电影
movies.unique = movies.df %>% tbl_df() %>% distinct(id, .keep_all = T)

# 写出数据
write.csv(movies.unique, file = 'data/douban_movies_unique_R.csv', row.names = F)

这个爬虫非常的简单,如同张宏伦课程中的那样,我们并没有进行浏览器的伪装。尽管我们在函数中加了爬虫的时间限制,但是在实际运行中,考虑到程序运行的时间,我们对这一行代码进行了注释。我的代码在12月14号运行的,大概用了半个小时。爬取的结果重复记录有很多,总共有97931行(包含表头),去除重复后2572行。如同,张宏伦说的那样,这种爬取方法爬到的数据还是相对有限的。我把爬下来的有重复的数据放在了百度云盘上,要是大家想看看,可以点击这里下载。

后话

以前,看过一些用R爬取网页的例子,由于对爬虫的原理不很清楚,总是不明白如何限定爬虫的节点。看了张宏伦课程爬取豆瓣电影的这一节,对爬虫依靠依靠网页的节点来实现爬取网页内容有了更深入的了解。结合以前看的内容,以为会很轻松的通过R实现。可是,在具体的实现时,发现还是遇到了一系列的坑。其中,最大的坑是如何在R中把json数据转化为R的常用数据。在解决这个问题的时候,又搜索的了陈堰平老师的文章,感觉陈老师在R的世界也是无处不在呀。

- - - - - -

参考文章

1.爬取豆瓣电影数据

2.R和JSON的傻瓜式编程

3.用R获取flash中的数据

]]>
文本文件在R中的读写 http://xukuang.github.io/blog/2016/12/text-json/ 2016-12-13T04:56:12+00:00 Xu Kuang http://xukuang.github.io/blog/2016/12/text-json 本文主要讲述的普通文本文件、HTML文件和JSON文件在R中的读写。

普通文本文件的读写

所谓普通文本文件,主要是指由字符组成的文件。它的读写主要使用到了readLines()和writeLines()函数。这两个函数本身非常基础。需要强调的是,readLines()函数会把每行作为字符向量的一个元素(即’\n’为分隔符)读入,所以读入文件常会弹出类似的警告“Warning message: In readLines(“example1.txt”) : incomplete final line found on ‘example1.txt’“,这个不会影响结果。同样,writeLines()函数会把字符向量的每个元素作为一行写出,所以写出的文件常比R中的向量多一个空白行。

HTML文件的读写

HTML文件

HTML(超文本标记语言,HyperText Markup Language)是一种用于创建网页的标准标记语言。通过对HTML文件读取可以进一步在R中分析网页上的内容。在R中能读取HTML文件的包很多,这里主要借助rvest包的read_html()函数来实现。使用到的HTML文件来自于豆瓣网电影专题。为了防止豆瓣网构架调整,导致我们不能顺利读取,我们把这个网页放在这里变成永久链接(新的链接只有文字,不够美观,但是方便我们学习)。 无论如何,我们并不用R来编写HTML文件,所以也不牵涉到HTML文件的写出。

HTML文件的读入

library(rvest)
web = read_html('http://xukuang.github.io/blog/images', encoding = 'UTF-8')
web %>% html_nodes('div.tag-list label') %>% html_text() # 该命令执行后,显示一下结果说明运行成功
	#  [1] "\n            热门\n            "    
	#  [2] "\n            最新\n            "    
	#  [3] "\n            经典\n            "    
	#  [4] "\n            可播放\n            "  
	#  [5] "\n            豆瓣高分\n            "
	#  [6] "\n            冷门佳片\n            "
	#  [7] "\n            华语\n            "    
	#  [8] "\n            欧美\n            "    
	#  [9] "\n            韩国\n            "    
	# [10] "\n            日本\n            "    
	# [11] "\n            动作\n            "    
	# [12] "\n            喜剧\n            "    
	# [13] "\n            爱情\n            "    
	# [14] "\n            科幻\n            "    
	# [15] "\n            悬疑\n            "    
	# [16] "\n            恐怖\n            "    
	# [17] "\n            动画\n            "    

对于网页文件,我们当然也可以下载到本地,把函数read_html()中路径更改为文件所在的本地路径来读取。不过,这种方法不常使用。

JSON文件的读写

JSON文件在R中的读写主要使用了rjson包。

JSON

JSON用于描述数据结构,有以下形式存在。

  • 对象(object):一个对象以“{”开始,并以“}”结束,或以“[”开始,并以“]”结束。一个对象包含一系列非排序的名称/值对,每个名称/值对之间使用“,”分区。
  • 名称/值(collection):名称和值之间使用“:”隔开,一般的形式是:
{name:value}

一个名称是一个字符串; 一个值可以是一个字符串,一个数值,一个对象,一个布尔值,一个有序列表,或者一个null值。

  • 值的有序列表(Array):一个或者多个值用“,”分区后,使用“[”,“]”括起来就形成了这样的列表,形如:
[collection, collection]

  • 字符串:以”“括起来的一串字符。
  • 数值:一系列0-9的数字组合,可以为负数或者小数。还可以用“e”或者“E”表示为指数形式。
  • 布尔值:表示为true或者false。

举例

例1

{
    "table1": {
        "time": "130911",
        "data": {
            "code": [
                "TF1312",
                "TF1403",
                "TF1406"
            ],
            "rt_time": [
                130911,
                130911,
                130911
            ]
        }
    },
    "table2": {
        "time": "130911",
        "data": {
            "contract": [
                "TF1312",
                "TF1312",
                "TF1403"
            ],
            "jtid": [
                99,
                65,
                21
            ]
        }
    }
}

例2

[
{
     "text":"This is the text","color":"dark_red","bold":"true","strikethough":"true","clickEvent":
          {"action":"open_url","value":"zh.wikipedia.org"},
     "hoverEvent":
          {"action":"show_text","value":
               {"extra":"something"}
          }
},
{
     "translate":"item.dirt.name","color":"blue","italic":"true"
}
]

JSON文件的读取

JSON在R中就是一个拥有特定格式的字符串。在R中,除了可以通过fromJSON()函数直接读取本地的JSON文件;理论上,R中所有符合JSON格式的字符串向量都可以通过fromJSON()函数被转化为R中的列表。所以,这里我们有两种方法读取JSON文件。我们把上面JSON的两个实例分别保存为example1.json和example2.json来读取。JSON文件的读取主要使用到了。

方法一

通过fromJOSN()函数直接读取JSON文件为列表对象。

library(rjson)
json_data1 <- fromJSON(file ="example1.json")
json_data1
	# $firstName
	# [1] "John"
	# 
	# $lastName
	# [1] "Smith"
	# 
	# $sex
	# [1] "male"
	# 
	# $age
	# [1] 25
	# 
	# $address
	# $address$streetAddress
	# [1] "21 2nd Street"
	# 
	# $address$city
	# [1] "New York"
	# 
	# $address$state
	# [1] "NY"
	# 
	# $address$postalCode
	# [1] "10021"
	# 
	# $phoneNumber
	# $phoneNumber[[1]]
	# $phoneNumber[[1]]$type
	# [1] "home"
	# 
	# $phoneNumber[[1]]$number
	# [1] "212 555-1234"
	# 
	# $phoneNumber[[2]]
	# $phoneNumber[[2]]$type
	# [1] "fax"

	# $phoneNumber[[2]]$number
	# [1] "646 555-4567"
json_data2 <- fromJSON(file ="example2.json")
json_data2

	# [[1]]
	# [[1]]$text
	# [1] "This is the text"
	# 
	# [[1]]$color
	# [1] "dark_red"
	# 
	# [[1]]$bold
	# [1] "true"
	# 
	# [[1]]$strikethough
	# [1] "true"
	# 
	# [[1]]$clickEvent
	# [[1]]$clickEvent$action
	# [1] "open_url"
	# 
	# [[1]]$clickEvent$value
	# [1] "zh.wikipedia.org"
	#  
	# [[1]]$hoverEvent
	# [[1]]$hoverEvent$action
	# [1] "show_text"
	# 
	# [[1]]$hoverEvent$value
	# [[1]]$hoverEvent$value$extra
	# [1] "something"
	#
	# [[2]]
	# [[2]]$translate
	# [1] "item.dirt.name"
	# 
	# [[2]]$color
	# [1] "blue"
	# 
	# [[2]]$italic
	# [1] "true"

这里原JSON,除最内层都被解析为R的list类型,最内层则是向量类型。这种方法,适合直接读取本地JSON文件。

方法二

先通过readLines()函数读取JSON文件为字符向量,再通过fromJSON()函数转化为列表对象。

json_data1 <- fromJSON(paste(readLines("example1.json"), collapse=""))
json_data2 <- fromJSON(paste(readLines("example2.json"), collapse=""))

这种方法,适合于对R中符合JSON格式的字符向量的处理。由于网页的数据中常包含JOSN格式字符串,所以第二种方法在网页处理中比较好用。

R对象转化为JSON

toJSON()函数可以把R对象序列化为JSON串,以刚才的json_data2为例。

json_str<-toJSON(json_data2)
json_str
	# [1] "[{\"text\":\"This is the text\",\"color\":\"dark_red\",\"bold\":\"true\",\"strikethough\":\"true\",\"clickEvent\":{\"action\":\"open_url\",\"value\":\"zh.wikipedia.org\"},\"hoverEvent\":{\"action\":\"show_text\",\"value\":{\"extra\":\"something\"}}},{\"translate\":\"item.dirt.name\",\"color\":\"blue\",\"italic\":\"true\"}]"
cat(json_str)
	# [{"text":"This is the text","color":"dark_red","bold":"true","strikethough":"true","clickEvent":{"action":"open_url","value":"zh.wikipedia.org"},"hoverEvent":{"action":"show_text","value":{"extra":"something"}}},{"translate":"item.dirt.name","color":"blue","italic":"true"}]

R中一般的输出结果是带转义的输出(\”),用cat输出是标准的JSON串格式。

JSON输出到文件

writeLines(json_str1, "result1.json")
writeLines(json_str2, "result2.json")

举例

一个批量处理JSON文件的例子,数据为data.JSON

library(rjson)

fdlist <- fromJSON(file = 'data.JSON')
fdlist

fdm <- matrix(unlist(fdlist),ncol=4,byrow=T)
fddf <- data.frame(fdm)
head(fddf)

- - - - - -

参考文章:

  1. 维基百科:JSON
  2. R和JSON的傻瓜式编程
  3. 用R获取flash中的数据
]]>
《西游记》用字统计 http://xukuang.github.io/blog/2016/12/xiyouji/ 2016-12-11T06:48:53+00:00 Xu Kuang http://xukuang.github.io/blog/2016/12/xiyouji 目的

使用R统计《西游记》中:

  • 共出现了多少个不同的汉字;
  • 每个汉字出现了多少次;
  • 出现得最频繁的汉字有哪些;
  • 实现初步的可视化。

平台

所有代码在windows7系统上运行(采用windows7系统,足见我业余数据爱好者的本质。因为windows系统遇到了很多编码方式的坑,实属无奈。这里也希望自己能早日摆脱银子的限制,入mac的阵营)。

数据

《西游记》文本文件xyj.txt,4020行(段),2.2MB。

注意:这里通过链接从张宏伦博士Github上下载的数据文件的编码格式时UTF-8,在windows系统上使用R读取和写出数据要特别注意数据文件的编码格式。

实现

方案一

方案一借助stringr包对xyz.txt文件进行预处理并对每个字单独提取,然后借助dplyr包实现每个字出现次数的统计。

# 加载需要的R包
library(stringr)
library(dplyr)

# 读取数据
# 这里文件内容是中文,采用的UTF-8格式,所以对encoding进行限制
fw = readLines('data/xyj.txt', encoding = 'UTF-8') # 文件xyz.txt的4020行分别存入到了一个长度为4020的向量中

# 数据预处理和计算
# 去除向量中每个元素的开始和结尾的空格
fw.real = str_trim(fw)
# 去除向量中为空的元素
fw.real = fw.real[!fw.real == '']
# 对向量中每个字符进行拆分
fw.list = str_split(fw.real, '') # 结果是数据类型为列表
# 将数据的类型由列表转化为数据框
single = data.frame(ch = do.call('c',fw.list))
# 统计每个字出现的次数,并按次数由高到底排列
result = single %>% group_by(ch) %>% summarise(num = n()) %>% arrange(desc(num))

# 写出数据
# 在windows系统下,R写出的数据文件默认为gbk的编码方式
write.csv(result, 'data/result_r.csv', row.names = F)
# 通过参数fileEncoding,将R写出的数据文件设置为UTF-8的编码方式
write.csv(result, 'data/result_r_utf8.csv', row.names = F,fileEncoding = 'UTF-8')

这里简单举例说明向量中元素有空格(这里的空格中英文输入都可以)和值为空的元素的含义。例如,一个字符向量str1 = c(‘中国’, ‘’, ‘ 中国’, ‘ 中 国’, ‘ 中 国 ‘, ‘中 国’)。这个向量str1的第3、4和5个元素含有空格,分别含有1个、2个、3个和2个。向量str1的第2个元素为空。

方案二

方案二借助stringr包对xyz.txt文件进行预处理,借助tidytest包对每个字单独提取,然后借助dplyr包实现每个字出现次数的统计。

# 加载需要的R包
library(tidytext)
library(dplyr)
library(stringr)

# 读取数据
# 这里文件内容是中文,采用的UTF-8格式,所以对encoding进行限制
fw = readLines('data/xyj.txt', encoding = 'UTF-8') # 文件xyz.txt的4020行分别存入到了一个长度为4020的向量中

# 数据预处理和计算
# 去除向量中每个元素的开始和结尾的空格
fw.real = str_trim(fw)

# 方案二,不需要去除向量中为空的元素
# fw.real = fw.real[!fw.real == '']

# 统计每个字出现的次数,并按次数由高到底排列
result = fw_df %>%
  unnest_tokens(ch, text, token = 'characters') %>% group_by(ch) %>% summarise(num = n()) %>% arrange(desc(num))

# 写出数据
# 在windows系统下,R写出的数据文件默认为gbk的编码方式
write.csv(result, 'data/result_r.csv', row.names = F)
# 通过参数fileEncoding,将R写出的数据文件设置为UTF-8的编码方式
write.csv(result, 'data/result_r_utf8.csv', row.names = F,fileEncoding = 'UTF-8')

方案二使用tidytext包的unnest_tokens()函数实现了每个字的提取。unnest_tokens()函数的使用可以参考这里

可视化

这里按照The tidy text format的步骤和方法对《西游记》中出现次数大于5000的字进行简单的可视化。其实,这里对主要用字的可视化对分析《西游记》意义并不大,更多的是学习数据可视化的方法和整个用字统计处理流程。意义不大的原因有(这里的原因主要是张宏伦博士提出的,我也十分赞同):

  • 《西游记》主要用字很可能在其他文章中出现的字数也很高;
  • 与英文不同,中文字本身意义并不大,更多的要结合词语语境。

使用代码:

# 找出出现次数大于5000的非标点符号字符
# 结果中result的ch列的因子水平按出现次数排序
result = result  %>%
  filter(!ch %in% c(',', '。', ':', '“', '”', '!') & num > 5000) %>% mutate(ch = reorder(ch, num))

# 出图
 ggplot(result, aes(x = ch, y = num)) +
  geom_bar(stat = "identity", fill = 'red') +
  xlab(NULL) + ylab('次数') + coord_flip()

《西游记》主要字的使用次数

- - - - - -

参考资料

1.实战 西游记用字统计

2.The tidy text format

]]>
开篇 http://xukuang.github.io/blog/2016/12/full-stack-data-engineer/ 2016-12-05T14:28:35+00:00 Xu Kuang http://xukuang.github.io/blog/2016/12/full-stack-data-engineer 张宏伦,何许人也?上海交通大学的博士生。在我看来,他是一枚”真的大牛“。《全栈数据工程师养成攻略》足见他的”大牛“本性,这个系列课程不在于它有多难(不过,我相信厚积才能薄发,而一切把知识讲的不知所云才是耍流氓),而在于他精准的实现了课程期望达到的效果:

  1. 面向广大群众,之前有无相关基础皆可,力求在每期视频中讲清楚每一个点;
  2. 视频长度控制在15分钟以内(严格地讲,部分视频并没有在15分钟内,但是一点也没影响轻松学习的效果),这样大家看起来比较轻松,随便听听一期视频就结束了,所讲到的东西也掌握了。

这两个效果对我来说特别明显。比如,以前,通过网络我也学习过python的爬虫,可惜没有一次顺利爬出来结果的,总会遇到各种问题。遇到的问题如此之多,以至于我都以为自己太小白了,而网上所谓的高手都骗人的。这个系列教程让我明白,爬虫能成功,首先是因为网页没有意识到被你爬,或者不介意被你爬,甚至愿意让你爬。其次,要想爬成功,还要你对网页构架有一定的了解。爬虫失败,往往是因为网站注意到了,或者介意一直总是被爬,更改了网页架构,而我们又不懂网页编辑造成的。知道了这点,我才明白爬虫失败,并不是因为高手是骗子,尽管网上随便粘贴的高手实在不少,更多的是因为我太小白了。此外,我也学过一点SQL的知识,但是总不太明白它的用途。这个课程,让我初步了解了SQL的用途,同时让SQL与现有的知识连接起来了。

事实上,更重要的是,课程让我从数据分析的角度梳理了自己的知识。这个课程在数据分析和存储部分是通过python实现的,而我比较多使用R,所以特别希望能够通过R实现课程中的内容。所幸,结合自己的知识和网上的搜索,通过R实现了课程的几个案例:西游记用字统计、爬取豆瓣电影数据和用R操作MySQL数据库。《跟着宏伦学习全栈工程师》系列博文主要介绍了这些案例在R中实现的过程,然而,终究水平所限,部分案例只是实现了需求,并不清楚深层次的原因,还希望大家指教。此外,毕竟python和R各有所长,加上我的知识有限,这个系列博文可能最终只有这三个案例的实现。如果大家有了后续课程中案例在R中的实现方案,希望不吝赐教。

此外,张宏伦的这个系列课程已经在陈堰平老师的雪晴数据网上上线了。以前,我在学习R的过程中,也从雪晴数据网上学到了好多知识。最后,特别希望我的这个系列博文能作为张宏伦课程的后续延伸投稿到雪晴数据网上。

]]>