文字标注
前言:因为最近在尝试用cesium和gee结合做东西,需要用到图例。其中我的图是动态生成的,所以一时间不知道怎么结合gee做动态图例,后来我看到有人直接把它显示在目标图层里,这是个好办法。但是要做图例,首先要解决的文字标注问题。
以后关于js的代码我尽量放置可以运行的链接,不再贴代码~
关于讨论文字标注的论坛链接
例子1 简单文本标注
简短版本(函数压缩成一句) https://code.earthengine.google.com/c4e0809d820b716354989f3caa1fcdbb
完整版本https://code.earthengine.google.com/2fa108d7211cdf73c62b241594bc1753
更简洁版本(调用包)https://code.earthengine.google.com/9fc23889ec43983250dfecf5be08267f
此后的几个例子关于文字标注函数的引用,大家可参照上述三种方式

例子2 经纬度标注
https://code.earthengine.google.com/ad954e02518c397f4734e5d92c88e021

例子3 图幅标注
https://code.earthengine.google.com/922a780f9e6372367270b2b477e68d4d
例子4 多文字图层合并
https://code.earthengine.google.com/90083716c54e0e3c19855517e74e3967

原理很简单,就是GEE根据字号和字型存储了大量的字符栅格图像,比如如下:
https://code.earthengine.google.com/59b09ba4a8aa38a673d6e4176d3bf041


函数会根据你的字号和字型找到对应的图像,根据编码从中挑出你要的字符,经过重采样、投影变换等展示在你放置的位置上
Python代码
找了很久没有发现相关的Python函数或包,唯一可以查找的就是官方放在js package里的一个函数,于是只能自己手动改了,除了语法相关,还改了一些python里不适用的函数,如有错误,请批评指正!
def drawText(text, pos, scale, props):
text = ee.String(text)
ascii = {}
for i in range(32, 128):
ascii[chr(i%256)] = i
ascii = ee.Dictionary(ascii)
fontSize = "16"
if props and ('fontSize' in props.keys()):
fontSizee = str(props['fontSize'])
fontType = "Arial"
if props and ('fontType' in props.keys()):
fontSize = str(props['fontType'])
glyphs = ee.Image('users/gena/fonts/' + fontType + fontSize)
if props and ('resample' in props.keys()):
glyphs = glyphs.resample(props['resample'])
proj = glyphs.projection()
s = ee.Number(1).divide(proj.nominalScale())
north = ee.Algorithms.If(proj.transform().index("-1.0").lt(0), -1, 1)
glyphs = glyphs.changeProj(proj, proj.scale(s, s.multiply(north)))
class newfont:
def __init__(self):
self.height = ee.Number(glyphs.get('height'))
self.width = ee.Number(glyphs.get('width'))
self.cellHeight = ee.Number(glyphs.get('cell_height'))
self.cellWidth = ee.Number(glyphs.get('cell_width'))
self.charWidths = ee.List(list(map(int, ee.String(glyphs.get('char_widths')).split(',').getInfo())))
font = newfont()
font.columns = font.width.divide(font.cellWidth).floor()
font.rows = font.height.divide(font.cellHeight).floor()
def translate(coord, x, y):
x1 = ee.Number(coord.get(0)).subtract(x)
y1 = ee.Number(coord.get(1)).subtract(y)
return ee.List([x1, y1])
def toAscii(text):
def fun(char, prev):
return ee.List(prev).add(ascii.get(char))
return ee.List(text.split('').iterate(fun, ee.List([])))
def moveChar(image, xmin, xmax, ymin, ymax, x, y):
ll = ee.Image.pixelLonLat()
nxy = ll.floor().round().changeProj(ll.projection(), image.projection())
nx = nxy.select(0)
ny = nxy.select(1)
mask =nx.gte(xmin).add(nx.lt(xmax)).add(ny.gte(ymin)).add(ny.lt(ymax)).eq(4)
return image.mask(mask).translate(ee.Number(xmin).multiply(-1).add(x), ee.Number(ymin).multiply(-1).subtract(y))
codes = toAscii(text)
def getwidth(code):
return ee.Number(font.charWidths.get(ee.Number(code)))
charWidths = codes.map(getwidth)
alignX = 0
alignY = 0
alignX = ee.Number(charWidths.reduce(ee.Reducer.sum())).divide(2)
alignY = ee.Number(font.cellHeight).divide(ee.Number(2).multiply(north))
if props and ('alignX' in props.keys()):
if props['alignX'] == 'center':
alignX = ee.Number(charWidths.reduce(ee.Reducer.sum())).divide(2)
elif props['alignX'] == 'left':
alignX = 0
elif props['alignX'] == 'right':
alignX = ee.Number(charWidths.reduce(ee.Reducer.sum()))
if props and ('alignY' in props.keys()):
if props['alignY'] == 'center':
alignY = ee.Number(font.cellHeight).divide(ee.Number(2).multiply(north))
elif props['alignY'] == 'top':
alignY = 0
elif props['alignY'] == 'bottom':
alignY = ee.Number(font.cellHeight)
def computexpos(w, list):
list = ee.List(list)
lastX = ee.Number(list.get(-1))
x = lastX.add(w)
return list.add(x)
charX = ee.List(charWidths.iterate(computexpos, ee.List([0]))).slice(0, -1)
charPositions = charX.zip(ee.List.sequence(0, charX.size()))
def computeglyph(code):
code = ee.Number(code).subtract(32)
y = code.divide(font.columns).floor().multiply(font.cellHeight)
x = code.mod(font.columns).multiply(font.cellWidth)
return [x, y]
charGlyphPositions = codes.map(computeglyph)
charGlyphInfo = charGlyphPositions.zip(charWidths).zip(charPositions)
pos = ee.Geometry(pos).transform(proj, scale).coordinates()
xpos = ee.Number(pos.get(0)).subtract(ee.Number(alignX).multiply(scale))
ypos = ee.Number(pos.get(1)).subtract(ee.Number(alignY).multiply(scale))
def drawglyphs(o):
o = ee.List(o)
glyphInfo = ee.List(o.get(0))
gw = ee.Number(glyphInfo.get(1))
glyphPosition = ee.List(glyphInfo.get(0))
gx = ee.Number(glyphPosition.get(0))
gy = ee.Number(glyphPosition.get(1))
charPositions = ee.List(o.get(1))
x = ee.Number(charPositions.get(0))
i = ee.Number(charPositions.get(1))
glyph = moveChar(glyphs, gx, gx.add(gw), gy, gy.add(font.cellHeight), x, 0)
return glyph.changeProj(proj, proj.translate(xpos, ypos).scale(scale, scale))
textImage = ee.ImageCollection(charGlyphInfo.map(drawglyphs)).mosaic()
textImage = textImage.mask(textImage)
if props:
if 'textColor' in props.keys():
textColor = props['textColor']
else:
textColor = 'ffffff'
if 'outlineColor' in props.keys():
outlineColor = props['outlineColor']
else:
outlineColor = '000000'
if 'outlineWidth' in props.keys():
outlineWidth = props['outlineWidth']
else:
outlineWidth = 0
if 'textOpacity' in props.keys():
textOpacity = props['textOpacity']
else:
textOpacity = 0.9
if 'textWidth' in props.keys():
textWidth = props['textWidth']
else:
textWidth = 1
if 'outlineOpacity' in props.keys():
outlineOpacity = props['outlineOpacity']
else:
outlineOpacity = 0.4
textLine = textImage.visualize("b1", None, None, None, None, None, textOpacity, [textColor], True)
if textWidth > 1:
textLine.focal_max(textWidth)
if not props and (props and(not ('outlineWidth' in props.keys()))):
return textLine
textOutline = textImage.focal_max(outlineWidth).visualize("b1", None, None, None, None, None, outlineOpacity, outlineColor, True)
return ee.ImageCollection.fromImages(ee.List([textOutline, textLine])).mosaic()
else:
return textImage
point = ee.Geometry.Point([12.39,4.07])
string = 'PIKACHU'
props = {'fontSize': 32, 'textColor': '000000'}
text = drawText(string, point, 117407, props) #调用函数
ee.mapclient.addToMap(text)
本地Python运行效果

drawText(text, pos, scale, props) (字符串,位置,分辨率,字体属性)
props里可以修改的是字体的字型、字号、颜色、字体对于给定位置的相对位置、外轮廓颜色等,比如:text =drawText(‘PIKACHU’, ee.Geometry.Point([12.39, 4.07]), 117407, {‘fontSize’: 32, ‘textColor’: ‘FFFF00’, ‘alignX’: ‘left’, ‘textOpacity’: 0.7, ‘outlineColor’: ‘000000’,‘outlineWidth’: 4})
alignX、alignY修改相对位置,alignX三个可选参数为left、centre、right,alignY三个可选参数为top、bottom、center,

字背景是灰色的是因为网不好,加载底图失败了。。。。
明、后天应该会更新图例部分(感觉做不完。。。)
也可能明后天做完之后,等到答辩完下周再更新博客。。。