flask交互式数据可视化_Python / Flask数据可视化和交互式地图

flask交互式数据可视化

您是否曾经想创建一个交互式数据可视化地图? 在我最近的副项目中,我创建了一个非常酷的可视化工具,以了解病毒如何在美国传播。 如果您想查看完成的站点,可以单击此处:

http://ethanszombies.herokuapp.com

现在,我将逐步介绍创建此文件的想法,并逐步说明如何创建自己的文件。 我知道可能有更好/更有效的方法来执行此操作,因此,如果您正在阅读本文,并且有更好的主意,请随时分享。 以下是此过程如何为我工作的细目。 我真的将这个项目分为两个部分。 第一部分是收集数据。 第二部分是用户部分,因此用户可以使用我们在第一部分中处理过的数据。 以下是此工作流程外观的流程图:

1-我们要创建什么? — — — — — — — — — — — — — — — — — — —

为此,尽管我确实想制作一个模拟病毒爆发的地图,但我要关注的病毒是僵尸病毒。 根据数小时的非常重要的研究,我发现了有关僵尸病毒通常如何传播的一些关键点:

1.僵尸病毒在人口稠密的地区(如内城区)传播得更快。
2.僵尸笨拙且不协调,使不利的地形变得困难。 因此,高海拔地区会使僵尸病毒传播更加缓慢。
3.虽然僵尸病毒的标准传播仅限于四处走动并咬人的僵尸,但如果被感染的人试图逃离汽车或其他车辆,则病毒可以更快地传播,从而使道路和州际公路更容易快速传播传播病毒。

当然,有足够的数据需要考虑,例如天气,气候或军方会对病毒传播产生影响,但是,在事情变得太疯狂之前,我们将从跟踪这三个数据点开始。1.人口密度,2.高程,3.州际公路。

2. —我们需要考虑哪些考虑因素? — — — — — — — — — — — — — — — — — — —

假设我们有一张美国地图,并且地图上的每个区域都是白色。 我们可以通过更改像素的颜色或将div更改为其他颜色来表示受感染的人。

一个。 时间间隔

首先,我们需要确定一个时间间隔。 此间隔可能是1秒,甚至更少。 每个时间间隔将代表对感染时间的实际测量,例如感染后一个小时或一天。

b。 在每个间隔做出决定

然后,我们可以模拟该div的动作。 在每个时间间隔,我们都需要确定受感染的块在何处移动,其移动到那里的速度以及是否感染任何人。

我们可以使用有关每个领域的数据来做出那些决定。

感染
  1. 人口密度将确定感染者在每个间隔内是否感染以及感染了多少其他人。 如果受感染的街区位于人口稠密的地区,它将感染许多人。 如果没有,它可能不会感染任何人。
速度
  1. 海拔将是速度的一个因素。 在每个时间间隔,被感染的街区都会移动一定的距离,但是如果海拔较高,则该距离会更短。
方向
  1. 州际公路将主要影响方向。 我们可以将每个受感染块的标准移动设置为随机模式,但是如果僵尸在高速公路上或高速公路附近绊倒,则其方向将在高速公路上保留一段时间。

3. —我们如何将想要的数据获取到地图上? — — — — — — — — — — — — — — — — — — —

第一步是使用我们需要的数据对地图进行编码。 对我来说,执行此操作的一种方法似乎是创建一个特定尺寸的地图。 就我的目的而言,我认为1150px X 768px应该可以正常工作。

接下来,我们需要确定一个僵尸将在地图上占据多少空间。 经过一些测试,我发现大约5px X 5px的区域就足够了。 除此之外,它似乎笨拙。 无论如何,要处理的数据太多,以至于不断消耗资源。

确定适当的地图尺寸后,我的下一步是在地图顶部创建一个叠加层。 此叠加层将包含我需要的大小的按钮(每个5px * 5px)。

对于人口密度,首先,我将创建最大人口密度为10,最小人口密度为0。这些数字是任意的,仅用于表示密度的变化,但不一定与实际的密度相对应。人口数。

尽管上述示例并未按比例扩展,但至少可以在此处看到该想法。 通过创建一个覆盖在地图顶部的网格,我们可以将数据编码到网格的每个块中,这将根据爆发到达的块来更改爆发React的方式。

我的想法是您可以单击每个按钮,并且每次单击时,数字(密度)将增加1。如果我们有40,000个按钮,则单击每个按钮似乎是不合理的,因此,我可以选择将该事件绑定到鼠标悬停上使数据输入更快。 在mouseover事件上更改颜色也是一个好主意,因此更容易跟踪哪些div包含哪些值。 既然我们已经考虑了伪代码,是时候开始实际设置文件并编写一些实际代码了,因为我们对要创建的内容以及创建方式有了更清晰的了解它。 在许多项目中,在编写任何代码之前,我会花费大量时间进行设计,这最终会使代码更加井井有条。

文件设置— — — — — — — — — — — — — — — — — — — —

我们最终将拥有的文件结构可能看起来像这样:

首先,我们可以使用命令行创建大部分内容。 其中一些文件(例如density.txt和densitydata.json)将在项目的第一部分中创建。

在命令行上,执行以下操作:

mkdir <project folder name> cd <project folder name>

现在,我们将在命令行上创建所有初始文件:

touch app.py .gitignore README.md requirements.txt runtime.txt mkdir templates mkdir static cd templates touch base.html cd .. cd static touch main.css

接下来,如果我们要创建一个git存储库并部署在heroku上,那么这是一个不错的地方。

git init

然后,如果我们设置了一个heroku帐户,则可以通过运行以下命令创建一个新的heroku项目:

heroku create <project name>

在开始安装依赖项和库之前,我们肯定要在Python中设置虚拟环境。 为此,我们可以运行以下命令:

pyvenv-3.6 env (substitute your python version here)

接下来,我们将如下激活该环境:

source env/bin/activate

在命令行中,您现在将在项目文件夹之前看到(env),以使您知道正在运行的虚拟环境。 如果从这里开始一直出现错误,提示python无法找到您已安装的模块,请检查您是否仍在使用虚拟环境。 如果不是,则再次运行最后一个命令。

接下来,由于flask是我们需要的主要依赖项,因此我们可以安装它。

pip install flask

如果我们决定在heroku上运行它,我们需要告诉它我们正在运行哪个python版本,我们可以将其添加到runtime.txt文件中:

echo "python-3.6.4" >> runtime.tx (or whatever your version is)

如果我们正在使用heroku,我们也想安装gunicorn:

pip install gunicorn

然后将以下文本添加到我们的Procfile中:

echo "web: gunicorn app:app" >> Procfile

最后,我们将运行pip Frozen以更新我们的requirements.txt文件:

pip freeze > requirements.txt

太酷了,既然一切都已完成,上面文件树中的大多数文件都应该在那儿,并且我们已经准备好摇滚。

回到前面的流程图,这是我们首先要研究的领域:

CSS — — — — — — — — — — — — — — — — — — —

基于我们之前讨论的工作流程,我们需要的第一件事是一张地图图像,我们可以在其上方覆盖按钮网格。 为此,我们将保存一张适合我们的地图,并将其用作div或element的背景图像。 我们还将其设置为适当的尺寸。 这将放入我们之前创建的main.css文件中:

#body { background-image: url('/static/states.png'); background-size: contain; background-repeat: no-repeat; background-size: 1150px 768px; margin: 0px; padding: 0px; display: flex; flex-flow: row wrap; justify-content: flex-start; align-items: flex-start; width:1150px; height:768px; border:black solid 2px; }

我们还将在这里创建两个按钮类。 当用户单击或活动的僵尸块感染另一个块时,我们会将其从一个CSS类更改为另一个CSS类。 这是我创建的类。 “ .btn”类是默认按钮类,“。active”是激活的类:

.btn { width: 4.5px; height:4.8px; background-color: transparent; margin: 0px; padding: 0px; font-size: 1px; } .active { width: 4.5px; height:4.8px; /* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#136325+0,305937+100&1+15,0+88 */ background: -moz-radial-gradient(center, ellipse cover, rgba(19,99,37,1) 0%, rgba(23,97,40,1) 15%, rgba(44,90,53,0) 88%, rgba(48,89,55,0) 100%); /* FF3.6-15 */ background: -webkit-radial-gradient(center, ellipse cover, rgba(19,99,37,1) 0%,rgba(23,97,40,1) 15%,rgba(44,90,53,0) 88%,rgba(48,89,55,0) 100%); /* Chrome10-25,Safari5.1-6 */ background: radial-gradient(ellipse at center, rgba(19,99,37,1) 0%,rgba(23,97,40,1) 15%,rgba(44,90,53,0) 88%,rgba(48,89,55,0) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#136325', endColorstr='#00305937',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ margin: 0px; padding: 0px; font-size: 1px; border-radius: 25%; } .btn:hover { cursor: pointer; }

HTML — — — — — — — — — — — — — — — — — — — —

然后,我们可以继续创建CSS中指示的实际HTML。 这将放入我们之前创建的base.html文件中:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <link type="text/css" rel="stylesheet" href="{{ url_for('static', filename='main.css') }}" /> <body> <div id="body"> </div> <button id="submitform" type="submit">SUBMIT</button> </body> <div id="formGoesHere"></div> </html>

JavaScript — — — — — — — — — — — — — — — — — —

接下来,我们将添加一些JavaScript。 我们将使用循环来创建所需长度的按钮。 如果您使用与我相同的尺寸,那么大约40,000个按钮似乎是正确的。 通常,您可能会有一个单独JavaScript文件。 虽然这可能是最佳做法,但我发现如果我编写的代码少于300行,那么将JavaScript包含在script标签中通常会更容易。 如果看起来我们将拥有更多,我们以后可以随时进行更改。

<script src=" https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js "></script> <script type='text/javascript'> $(document).ready(function(){ $(document).ready(function(){ for (var i = 0; i < 40000; i++) { var inputBtn = ` <div type="button" class="btn">0</div> `; $('#body').append(inputBtn); } }); </script>

接下来,我将为刚才创建的所有标签创建mouseover事件:

var color1 = '#fff600'; var color2 = '#ffc32b'; var color3 = '#e8a600'; var color4 = '#e88300'; var color5 = '#ce7502'; var color6 = '#ce3b01'; var color7 = '#ad3201'; var color8 = '#7a2402'; var color9 = '#561a02'; var color10 = '#1e0800'; $('body').on('mouseover', '.btn', function () { var currentVal = $(this).html(); console.log(currentVal); var newVal = parseInt(currentVal) + 1; if (newVal > 10){ newVal = 10 } var color1 = '#fff600'; var color2 = '#ffc32b'; var color3 = '#e8a600'; var color4 = '#e88300'; var color5 = '#ce7502'; var color6 = '#ce3b01'; var color7 = '#ad3201'; var color8 = '#7a2402'; var color9 = '#561a02'; var color10 = '#1e0800'; $('body').on('mouseover', '.btn', function () { var currentVal = $(this).html(); console.log(currentVal); var newVal = parseInt(currentVal) + 1; if (newVal > 10){ newVal = 10 } $(this).html(newVal); if ($(this).html() == 1){ $(this).css('background-color', color1); } else if ($(this).html() == 2){ $(this).css('background-color', color2); } else if ($(this).html() == 3){ $(this).css('background-color', color3); } else if ($(this).html() == 4){ $(this).css('background-color', color4); } else if ($(this).html() == 5){ $(this).css('background-color', color5); } else if ($(this).html() == 6){ $(this).css('background-color', color6); } else if ($(this).html() == 7){ $(this).css('background-color', color7); } else if ($(this).html() == 8){ $(this).css('background-color', color8); } else if ($(this).html() == 9){ $(this).css('background-color', color9); } else if ($(this).html() == 10){ $(this).css('background-color', color10); } });

在前面的示例中,每个块或数组元素的值都将在0到10之间。如果我们想返回并编辑此表单和数据,以便在每个块上存储有关人口和海拔的数据,则可能需要以不同的方式增加该值,或存储一个true / false值。 我们随时可以在此处更改输入,但是要根据要存储的数据将其写入后端的新文件。 稍后我们将更多地讨论这个想法,但只是要考虑的事情。

最后,我将创建一个表单,该表单使我可以将烧瓶前端的数据发送到后端的python。 然后,我可以操纵数据并创建哈希。

var inputArr = '' $('#submitform').click(function(){ $(".btn").each(function(){ var input = $(this).html(); inputArr += ("," + input); }); var form2 = ` <form action="form1" id="myForm" method="post"> <input value="${inputArr}" name="t1"/> </form> `; console.log(inputArr); $('#formGoesHere').append(form2); $('#myForm').submit(); }); });

即使我们已经在前端创建了表单和所有内容,但实际上尚未将其连接到任何内容。 为了将这些数据连接到python,我们需要修改app.py文件,并使用Flask请求从base.html文件中接收数据。 至此,我们现在在流程图中:

Python — — — — — — — — — — — — — — — — — — —

在app.py中,让我们继续导入完成这项工作所需的内容:

from flask import Flask, request, render_template

接下来,我们将定义应用程序:

app = Flask(__name__)

最后,我们将定义将与我们的base.html文件关联的路由,该路由将成为主要路由(“ /”):

@app .route('/', methods=['GET', 'POST']) def searchTopic(): return render_template('base.html')

此路线将呈现页面,但我们还需要为表单创建路线。 如果返回到我们编写的html,则该表单的操作为“ form1”,这将是我们用于表单数据的路线。

@app .route('/form1', methods=['GET', 'POST']) def getFormData(): data = request.form['t1'] f = open('file.txt', 'w') f.write(data) f.close() return render_template('base.html')

在这里,我们在app.py中的路由“ / form1”与html中表单的操作相关联。 输入格式“ t1”与app.py中的request.form ['t1']相关联。

最后,我们将以下行添加到app.py文件的底部:

if __name__ == '__main__': app.run()

现在,如果我们提交表单,该数据将被保存为变量“ data”。 然后,我们将打开一个名为file.txt的文件,并将“数据”变量写入该文件。 现在,我们可以遍历文件中的数据,并将其与以后可能收集的其他数据一起转换为JSON。

返回HTML / JavaScript — — — — — — — — — — — — — — — — — — — —

如果您这样设置,则可以在mousever上看到,我们正在更改每个div中html的值以及颜色。 颜色使您可以轻松查看已更改和未更改的内容。 提交表单时,我可以将divs的值作为数组发送给python。 输入过程可能如下所示:

控制台日志记录了每个div的值,您可以在创建它时看到区域图。 一旦有了所需的所有地图数据,就可以从JavaScript文件中注释该代码,因为实际上不需要使用它来运行模拟。 但是,如果我们想为任何新类型的数据制作新的地图,则非常方便。 就我而言,我提交了一张仅包含人口数据的地图,另一张包含了海拔数据的地图,依此类推……然后将每个列表组合成python中的哈希。

我们通过前端输入的数据被解释为数组或逗号分隔的值。 地图数据基本上是40000个元素的数组,范围从0到10,如下所示:

[0,0,0,0,0,0,1,1,2,3,4,0,0,0,0,0,0,0,5,6,6,7,7,7,4 ,1,0……..]

4 —将原始数据组装成JSON — — — — — — — — — — — — — — — — — — —

在python中,每个列表将具有相同数量的索引,也就是说,在列表1中,索引552处的数组将对应于网格中的第552个div。 因此,我将遍历一个列表,但同时检查另一个列表,而不必遍历两个列表。 在下面的示例中,我有一个包含人口数据的列表,还有一个包含有关当前区块是否为水的数据的列表。

import json with open('population.txt') as f: file1 = [line.rstrip() for line in f] with open('file.txt') as f: file2 = [line.rstrip() for line in f] array = [] for idx, i in enumerate(file1): arr = i.split(",") waterArr = file2[idx].split(",") x = 0 for index, a in enumerate(arr): myObj = { "population": 0, "water": 0, } if int(a) > 9: myObj['population'] = 8 elif int(a) is 9: myObj['population'] = 7 elif int(a) is 8: myObj['population'] = 6 elif int(a) is 7: myObj['population'] = 5 elif int(a) is 6: myObj['population'] = 4 elif int(a) is 5: myObj['population'] = 3 elif int(a) is 4: myObj['population'] = 2 elif int(a) is 3: myObj['population'] = 1 elif int(a) < 3: myObj['population'] = 0 if waterArr[index] == '1': myObj['water'] = 1 array.append(myObj) with open('density2.json', 'w') as outfile: json.dump(array, outfile)

然后,我将数据转换为json,并将其另存为json文件。 修改后的json数据列表如下所示:

...{"water": 1, "population": 0}, {"water": 0, "population": 0}, {"water": 1, "population": 0}, {"water": 0, "population": 0}, {"water": 0, "population": 0}, {"water": 0, "population": 0}, {"water": 0, "population": 0}, {"water": 0, "population": 0}, {"water": 0, "population": 1}, {"water": 0, "population": 1}, {"water": 0, "population": 0}, {"water": 0, "population": 0}, {"water": 0, "population": 1}, {"water": 0, "population": 1}, {"water": 0, "population": 5}, {"water": 0, "population": 0}, {"water": 0, "population": 0}, {"water": 0, "population": 0},...

数组中的每个元素都包含有关该街区的人口以及该街区是否是水的数据(因为我们不希望僵尸漫步入海吗?)

结束部分1 — — — — — — — — — — — — — — — — — — — —

至此,我们至少已经收集了一些数据。 我们总是可以使用我们创建的文件返回,并输入有关海拔或人口年龄或我们认为与之相关的任何数据。 我们只需要给新文件起一个新的名字,这样我们就不会覆盖以前的文件。 然后,我们可以将其添加到python的循环中,并将其他数据添加到JSON数据中。

在继续之前要考虑的一件事是,由于这是一个相当小的项目,因此我不会为不同的功能制作其他文件。 我只是要注释掉不需要的部分。 由于我们正在从该项目的第一部分移至第二部分,因此我们可以注释掉与收集,组织或收集数据有关的所有代码。 这包括将文本文件转换为哈希的前面几行,以及创建和提交表单数据JavaScript。 但是,如果您更容易跟踪单独的文件,则可以这样做。 请记住,您拥有的文件结构将与我的不同。

部分2 — — — — — — — — — — — — — — — — — — — —

现在我们有了这些数据,我们想要将其作为json发送到前端。 我们可以通过烧瓶形式做到这一点。

在app.py中,在主要途径上,我们仅包含一个从python获取数据的函数。 就像我前面提到的,我觉得将这个文件中的先前代码注释掉会更容易,该代码将文本文件组合成JSON,并将这些行包括在注释掉的部分下面。 但是,如果您想使用一个新文件,也可以:

------- IN TEST.PY ------------------- with open('density2.json') as f: popDensity = json.load(f) def getData(): return popDensity

调用主路由('/')时,我们将从test.py模块调用getData函数,并将其作为输出返回以在JavaScript文件中使用。 我们还将修改我们之前创建的app.py路由,以接受并将此数据发送到前端。 我们还将在顶部包含一个import语句,以导入包含我们要使用的功能的模块test.py:

from test import getData

然后,我们将该函数添加到主路径中以获取数据:

@app .route('/', methods=['GET', 'POST']) def searchTopic(): output = getData() return render_template('base.html', result=output)

5 —使用前端的JSON数据影响模拟。 — — — — — — — — — — — — — — — — — — —

在我们JavaScript文件中,我们可以使用flask来检索数据:

$(document).ready(function(){ var data = {{ result|tojson }};

现在,变量数据包含我们在“ /”路由函数中传递的结果。

我的想法是使用元素属性形式的JSON数据对每个div进行编码。 我将从“水”,“人口”和“方向”的属性开始。 “水”和“人口”是从python传入的属性,“方向”将完全由JavaScript控制。 我们将从创建这些属性开始,以便可以在元素中使用它们:

var population = document.createAttribute("population"); var direction = document.createAttribute("direction"); var isWater = document.createAttribute("isWater");

我们的元素可能看起来像这样:

<div id="2554" population="5" direction="northeast" isWater="notWater" type="button" class="btn"></div>

现在,我们不想对每个div进行硬编码,因此我们将其循环执行。

var directionArray = ['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw']; for (var i = 0; i < data.length; i++) { population.value = data[i].population; direction1 = directionArray[Math.floor(Math.random() * directionArray.length)]; var inputBtn = ` <div id="${i}" population="${data[i].population}" direction="${direction1}" isWater="${data[i].water}" type="button" class="btn"></div> `; $('#body').append(inputBtn); }

再一次,希望我们已经注释掉了用于创建数据映射JavaScript,但是这段代码看起来与我们之前的代码非常相似。 最初,当我们进入该项目的第一部分时,我们使用JavaScript创建HTML div,每个div为空白。 现在,在我们的for循环中,我们还将属性分配给每个元素,然后再将其附加到#body。

因为僵尸无论如何都会表现出不稳定的行为,所以我将随机地将其初始行进方向随机设置。 以下是我们如何确定僵尸的方向的方法:

实施间隔— — — — — — — — — — — — — — — — — — — — — —

如果一个特定的块被感染,如上所示,并且该块是div#456,则它可以从其当前位置传播8个可能的方向:n,ne,e,se,s,sw,w,nw。 如果我们将这些div视为数组,则向东的方向将为当前位置+1。向西的方向将为当前位置-1。 南北取决于行中元素的数量。 在我的情况下,北为-255,南为+ 255,依此类推。 如果在任何给定的时间间隔内,当前受感染的块不在人口稠密的区域中,则它将移动到新的块。 现在,如果此时我们什么也不做,则已经为每个块设置了僵尸方向。 在每个时间间隔,我们可以检查给定块的方向,然后将其移动到新的对应空间。 但是,让我们想象一下我们这样做了,当前块的方向为“ ne”。 这是每个时间间隔的样子:

显然,我们可能希望对此进行随机化。 回到我们之前讨论的时间间隔,我们需要在每个时间间隔做出以下决定:运动的方向,运动的速度以及是否感染任何人。 我们的逻辑可能看起来像这样:

现在我们有了一些伪代码,这是一些实际代码。 我们将从onClick事件开始,它将是触发所有其他事件的第一个事件:

$('body').on('click', '.btn', function () { let color9 = colorArr[Math.floor(Math.random() * colorArr.length)]; $(this).attr('isActive', 1); $(this).removeClass('btn'); $(this).addClass('active'); $('.btn').click(false); });

在单击时,我们删除btn的类,禁用其他任何按钮单击,并添加active的类。 现在,当我们获得setInterval函数时,它将拾取该块。 接下来,我将创建一个包含两个元素的数组,分别为1和0:

var changeArr = [0,1];

在设置间隔函数中,每次找到一个块时,我们都会随机选择这两个数字之一,就像掷硬币一样。 如果得到1,则将更改当前块的direction属性。 如果我们得到0,我们将保持相同的方向。

setInterval(function(){ var buttons = $( ".active" ).toArray();

在setInterval函数内部,我们要做的第一件事是获取所有活动按钮的数组。 起初,只有一个。

接下来,我们将获得所有相邻的按钮,并将它们放置在数组中。 这些按钮将成为我们的定向按钮,北,南,东,西等。

var currentID = $(buttons[i]).attr('id'); var id1 = parseInt(currentID)+1; var id2 = parseInt(currentID)+254; var id3 = parseInt(currentID)+255; var id4 = parseInt(currentID)+256; var id5 = currentID-1; var id6 = currentID-254; var id7 = currentID-255; var id8 = currentID-256; var adjacentbuttons = [$('#'+id1+''),$('#'+id5+''),$('#'+id7+''),$('#'+id8+''),$('#'+id6+''),$('#'+id3+''),$('#'+id4+''),$('#'+id2+'')];

接下来,如果人口密度超过10,我们将采取以下措施:

if($(buttons[i]).attr('population') >= 10){ $(adjacentbuttons[2]).attr('isActive', 1); $(adjacentbuttons[2]).removeClass('btn'); $(adjacentbuttons[2]).addClass('active'); $(adjacentbuttons[4]).attr('isActive', 1); $(adjacentbuttons[4]).removeClass('btn'); $(adjacentbuttons[4]).addClass('active'); $(adjacentbuttons[0]).attr('isActive', 1); $(adjacentbuttons[0]).removeClass('btn'); $(adjacentbuttons[0]).addClass('active'); $(adjacentbuttons[6]).attr('isActive', 1); $(adjacentbuttons[6]).removeClass('btn'); $(adjacentbuttons[6]).addClass('active'); $(adjacentbuttons[5]).attr('isActive', 1); $(adjacentbuttons[5]).removeClass('btn'); $(adjacentbuttons[5]).addClass('active'); $(adjacentbuttons[1]).attr('isActive', 1); $(adjacentbuttons[1]).removeClass('btn'); $(adjacentbuttons[1]).addClass('active'); $(adjacentbuttons[3]).attr('isActive', 1); $(adjacentbuttons[3]).removeClass('btn'); $(adjacentbuttons[3]).addClass('active'); }

我们基本上是从阵列中选择几个,然后将它们全部激活。 本质上,如果偶然发现人口稠密的区域,它将感染许多其他相邻的块。 我们也可以为其他密度添加逻辑。 例如:

else if($(buttons[i]).attr('population') == 3){ $(adjacentbuttons[7]).attr('isActive', 1); $(adjacentbuttons[7]).removeClass('btn'); $(adjacentbuttons[7]).addClass('active'); }

如果密度仅为3,则仅感染另一个相邻的块。

方向–图库图片–图库图片

这是我在每个方向上使用的逻辑:

if($(buttons[i]).attr('direction') == 'n'){ let change = changeArr[Math.floor(Math.random() * changeArr.length)]; if (change == 0){ $(buttons[i]).attr('isActive', 0); $(adjacentbuttons[2]).attr('isActive', 1); $(adjacentbuttons[2]).attr('direction', 'n'); $(adjacentbuttons[2]).removeClass('btn'); $(adjacentbuttons[2]).addClass('active'); $(buttons[i]).removeClass('active'); $(buttons[i]).addClass('btn'); } else if (change == 1 && $(buttons[i]).attr('isWater') != 1){ let newDirection = directionArray[Math.floor(Math.random() * directionArray.length)]; $(buttons[i]).attr('isActive', 0); $(adjacentbuttons[2]).attr('isActive', 1); $(adjacentbuttons[2]).attr('direction', newDirection); $(adjacentbuttons[2]).removeClass('btn'); $(adjacentbuttons[2]).addClass('active'); $(buttons[i]).removeClass('active'); $(buttons[i]).addClass('btn'); } else if ($(buttons[i]).attr('isWater') == 1){ $(buttons[i]).removeClass('active'); $(buttons[i]).addClass('btn'); } }

基本上在这里,我正在寻找每个间隔的三件事。

我从选择数组中选择一个随机选择。

2 —方向会改变吗? 如果没有,我会以一种快乐的方式发送它。

3 —如果方向确实发生变化,则从方向数组中随机选择一个新方向,并将其用作新方向。

4 —除非是水…否则我将按钮设置回“ btn”而不是“ active”

结论:

老实说,这是很简单的事情,而且很基础。 但是,您可以做更多的事情。 即使在此示例中,我们也可以包含尚未完成的有关海拔的数据。 我们可以包括所有其他种类的数据。 如果您正在寻找一种有趣的方式来创建快速的交互式地图,希望对您有所帮助。 我最大的担心是setInterval是解决这一问题的真正资源密集型方法,而且我敢肯定会有更好的解决方案。 如果您有任何想法或其他反馈,请随时分享。 谢谢!

翻译自: https://hackernoon.com/python-flask-data-visualization-interactive-maps-30bc4e872a14

flask交互式数据可视化

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值