Tableau-地图系列

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tableau-地图系列相关的知识,希望对你有一定的参考价值。

参考技术A 绘制不同省份电量销售填充地图:

方法:将“省市”、“地市”分别转换对应的地理角度,双击“省份”,拖动“当期值”至颜色位置并编辑颜色,拖动“省份”至标签,编辑未识别值(可筛选掉),更改标签正确省份名称。

地图格式设置

地图---地图层---样式(普通、浅色、黑色)---冲蚀(100%,地图背景是白色)---地图层(主要底图、土地覆盖、海岸线、国家名称)。操作对比一下就看出效果啦~

方法:双击“省份”,拖动“省份”至颜色(编辑颜色),拖动“用电类别”至列,“统计周期”至行,如下:

展开“+”内容,可以看到季度、月的售电情况,用电类别下拉列表---排序---手动对用电类别排序,符合实际逻辑,设置所有用电类别名称的格式,点击统计周期---右键---隐藏行字段标题即可隐藏统计周期。然后工作表---导出---图像。

绘制各省市售电量的混合地图:

方法:类似圆环图。双击“省份”---拖动“当期值”至颜色---行位置ctrl+鼠标左键拖动再生成1个纬度,下拉列表选双轴---在纬度下面移除“当期值”---拖动“同期值”至大小(可修改形状)---编辑颜色或拖至“月度计划值”至颜色---地图---地图层---冲蚀100%。

这个混合地图表达3个信息:1)蓝色深浅代表各省售电量的当期值,颜色越深,售电量越大;2)圆形大小代表各省售电量的同期值,圆形越大,售电量越大;3)红色代表各省售电量的月度计划值,颜色越深,售电量越大。

绘制英国公园的多边形地图: 根据每个点的经纬度顺时针形成的多边形

方法:转换相应的地理角度(经纬度)---双击“纬度”---双击“经度”---分析,勾掉“聚合度量”---标记“多边形”---拖动“点ID”至路径---拖动“公园名称”至颜色---地图,地图层,样式调整为普通,冲蚀20%---勾选地名(海岸线可操作对比下)---由于无法添加标签,所以可以手动添加标注,注明公园名称。

自定义地理编码:只是用符号地图,要求导入文件格式为csv,需要包括新的地理角色、维度及经度且列名称必须用英文、首字母要大写(如国家:Country)。

方法:地图---地理编码---导入自定义地理编码

1.扩展现有角色: 可以添加某一城市,需知道它的经纬度信息

2.添加新的角色: 不仅可以显示国家、省份、市,还可以添加其他类型,如大学、医院等。

3.添加新的分层结构: 如对国家公园添加新的分层结构,有三个字名称:国家、公园名称、子景点名称。

地图---背景地图---地图服务---添加---WMS服务器

自定义背景图 :香港地铁图像为例,要有图像和数据表

方法:地图---背景图像---图片---添加图像---浏览位置,填入像素---应用---确定---拖动“X"至列,“Y”至行,“line”至颜色,“station”至详细信息。

从 Tableau 地图中抓取数据

【中文标题】从 Tableau 地图中抓取数据【英文标题】:Scraping Data from a Tableau Map 【发布时间】:2020-11-11 11:16:57 【问题描述】:

我正在尝试获取伊利诺伊州纳洛酮配送中心的位置和名称,以开展关于阿片类药物危机的研究项目。

公共卫生部https://idph.illinois.gov/OpioidDataDashboard/可以从这里访问这个由画面生成的仪表板

我已经尝试了我能找到的一切。首先使用 Tableau 的界面更改 url 以“下载”数据。那只能让我下载一个 pdf 地图,而不是它背后的实际数据集。其次,我修改了我在 Stack Overflow 上见过几次的 python 脚本来尝试请求数据。但是,我认为它遇到了某种错误。代码如下。

url = "https://interactive.data.illinois.gov/t/DPH/views/opioidTDWEB_prod/NaloxoneDistributionLocations"

r = requests.get(
    url,
    params= 
        ":embed":"y",
        ":showAppBanner":"false",
        ":showShareOptions":"true",
        ":display_count":"no",
        "showVizHome": "no"
    
)
soup = BeautifulSoup(r.text, "html.parser")
print(soup)
tableauData = json.loads(soup.find("textarea","id": "tsConfigContainer").text)

dataUrl = f'https://tableau.ons.org.brtableauData["vizql_root"]/bootstrapSession/sessions/tableauData["sessionid"]'

r = requests.post(dataUrl, data= 
    "sheet_id": tableauData["sheetId"],
)

dataReg = re.search('\d+;(.*)\d+;(.*)', r.text, re.MULTILINE)
info = json.loads(dataReg.group(1))
data = json.loads(dataReg.group(2))

print(data["secondaryInfo"]["presModelMap"]["dataDictionary"]["presModelHolder"]["genDataDictionaryPresModel"]["dataSegments"]["0"]["dataColumns"])

感谢任何帮助。

【问题讨论】:

【参考方案1】:

编辑

我创建了一个tableau scraper library 来将工作表数据提取到熊猫数据框中。

代码更简单,但在您的情况下,您仍然需要使用 xsrf 令牌构建 URL:

from tableauscraper import TableauScraper as TS
import requests
from bs4 import BeautifulSoup

init_url = "https://idph.illinois.gov/OpioidDataDashboard/"
r = requests.get(init_url)
soup = BeautifulSoup(r.text, "html.parser")
paramTags = dict([
    (t["name"], t["value"])
    for t in soup.find("div", "class": "tableauPlaceholder").findAll("param")
])

url = f'paramTags["host_url"]trusted/paramTags["ticket"]paramTags["site_root"]/views/paramTags["name"]'

ts = TS()
ts.loads(url)
dashboard = ts.getWorkbook()

for t in dashboard.worksheets:
    # show worksheet name
    print(f"WORKSHEET NAME : t.name")
    # show dataframe for this worksheet
    print(t.data)

Try this on repl.it


原帖

这有点复杂,因为有以下几种组合:

存在 tsconfig textarea 的画面“配置页面”不是原始页面的一部分。该 url 是从一些 param html 标签动态构建的 它在 cookie 中使用了一个交叉伪造令牌,但为了获取该 cookie,您需要调用一个特定的 api,其 url 是从一些 param html 标记动态构建的 通过 tsconfig 参数,我们可以构建数据 url,正如您在其他 *** 帖子中找到的那样,例如 this、this 和 this

流程如下:

调用GET https://idph.illinois.gov/OpioidDataDashboard/,在类tableauPlaceholder的div下抓取param标签

从那里主机是:https://interactive.data.illinois.gov

从以前的param 标签,构建如下所示的“会话 URL”:

GET /trusted/ticket/t/DPH/views/opioidTDWEB_prod/MortalityandMorbidity

上面的 url 将仅用于存储 cookie(包括 cookie 中的 xsrf 令牌)

从之前的 param 标签,构建如下所示的“配置 URL”:

GET /t/DPH/views/opioidTDWEB_prod/MortalityandMorbidity

提取id为tsConfigContainer的textarea并从中解析json

从上面提取的 json 中构建“数据 url”,url 如下所示:

POST /vizql/t/DPH/w/opioidTDWEB_prod/v/MortalityandMorbidity/bootstrapSession/sessions/session_id

然后你有一个 json 响应,前面有一些字符串以防止json hijacking。你需要正则表达式来提取它,然后解析巨大的 json 数据

所需的所有网址都是这样的:

GET https://idph.illinois.gov/OpioidDataDashboard/
GET https://interactive.data.illinois.gov/trusted/yIm7jkXyRQuH9Ff1oPvz_w==:790xMcZuwmnvijXHg6ymRTrU/t/DPH/views/opioidTDWEB_prod/MortalityandMorbidity
GET https://interactive.data.illinois.gov/t/DPH/views/opioidTDWEB_prod/MortalityandMorbidity
POST https://interactive.data.illinois.gov/vizql/t/DPH/w/opioidTDWEB_prod/v/MortalityandMorbidity/bootstrapSession/sessions/2A3E3BA96A6C4E65B36AEDB4A536D09F-1:0

完整代码:

import requests
from bs4 import BeautifulSoup
import json
import re

s = requests.Session()

init_url = "https://idph.illinois.gov/OpioidDataDashboard/"
print(f"GET init_url")
r = s.get(init_url)
soup = BeautifulSoup(r.text, "html.parser")
paramTags = dict([
    (t["name"], t["value"]) 
    for t in soup.find("div", "class":"tableauPlaceholder").findAll("param")
])

# get xsrf cookie
session_url = f'paramTags["host_url"]trusted/paramTags["ticket"]paramTags["site_root"]/views/paramTags["name"]'
print(f"GET session_url")
r = s.get(session_url)

config_url = f'paramTags["host_url"][:-1]paramTags["site_root"]/views/paramTags["name"]'
print(f"GET config_url")
r = s.get(config_url,
    params = 
        ":embed": "y",
        ":showVizHome": "no",
        ":host_url": "https://interactive.data.illinois.gov/",
        ":embed_code_version": 2,
        ":tabs": "yes",
        ":toolbar": "no",
        ":showShareOptions": "false",
        ":display_spinner": "no",
        ":loadOrderID": 0,
)
soup = BeautifulSoup(r.text, "html.parser")
tableauData = json.loads(soup.find("textarea","id": "tsConfigContainer").text)

dataUrl = f'paramTags["host_url"][:-1]tableauData["vizql_root"]/bootstrapSession/sessions/tableauData["sessionid"]'
print(f"POST dataUrl")
r = s.post(dataUrl, data= 
    "sheet_id": tableauData["sheetId"],
)
dataReg = re.search('\d+;(.*)\d+;(.*)', r.text, re.MULTILINE)
info = json.loads(dataReg.group(1))
data = json.loads(dataReg.group(2))

print(data["secondaryInfo"]["presModelMap"]["dataDictionary"]["presModelHolder"]["genDataDictionaryPresModel"]["dataSegments"]["0"]["dataColumns"])

Try this on repl.it

【讨论】:

以上是关于Tableau-地图系列的主要内容,如果未能解决你的问题,请参考以下文章

Tableau10.5实用图形制作大全系列视频课程

Tableau可视化分析实战系列(三十一)-如何对超市销售数据进行可视化分析

如何在tableau导入地图

Tableau实战系列数据连接及数据准备

Tableau 背景地图

Tableau 地图