添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

之前在做项目的时候,遇到了一个问题:就是我想将单片机板子的传感器数据,实时上传到物联网平台,然后进行数字大屏显示。一开始使用的是 onenet平台 →多协议接入→应用管理来进行设置,奈何里面的一个组件少的可怜!

又看到它家的‘ 数据可视化View 功能!被他酷炫的数字大屏模板深深吸引了。

心想这不就我要找的模板吗?于是信誓旦旦的准备大概一场的时候:在我们选择一个2D项目模板,准备创建项目的时候,它跳出来一个对话框“ 提示氪金” (ps:新用户有7天的专业版试用资格,我当时要做项目的时候,已经过了!)

眼看着比赛的时间节点就快到了,于是咬咬牙,就买了两个月!

买了一个企业版的会员,买完回来发现:“里面的有些功能不能用!需要升级专业版会员!(腾讯svip直呼:“内行”)”没有办法了,只能展示用这个了。勉强将项目如期完成!

数字项目大屏项目做完后,我再想能不能自己来写一个数字大屏demo呢?恰好DF的‘’Mind+Python编程与智能设计大赛'正在进行中,于是就开始着手去实现这个想法!本教程将会带领你从零开始搭建一个:基于Pyecharts + Flask + Pinpong 智能家居数字大屏系统的项目!

1、安装pyecharts

Echarts 是一个由百度开源的数据可视化,凭借着良好的交互性,精巧的图表设计,得到了众多开发者的认可。而 Python 是一门富有表达力的语言,很适合用于数据处理。当数据分析遇上数据可视化时, pyecharts 诞生了。

简洁的 API 设计,使用如丝滑般流畅,支持链式调用囊括了 30+ 种常见图表,应有尽有支持主流 Notebook 环境,Jupyter Notebook 和 JupyterLab可轻松集成至 Flask,Django 等主流 Web 框架高度灵活的配置项,可轻松搭配出精美的图表详细的文档和示例,帮助开发者更快的上手项目多达 400+ 地图文件以及原生的百度地图,为地理数据可视化提供强有力的支持 具体开发文档详见 pyecharts开发文档

如何安装?

在mind+的python模式下:点击“库管理”→"图表"→"pyecharts"点击安装即可!

方法二:pip安裝

在mind+的python模式下:点击“库管理”→"pip模式"下:

输入:pip install pyecharts

(ps:因为我这里已经安装了,界面中提示了欢迎已经存在)

2、安装Flask

Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。它可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或Web服务的实现。另外,Flask还有很强的定制性,用户可以根据自己的需求来添加相应的功能,在保持核心功能简单的同时实现功能的丰富与扩展,其强大的插件库可以让用户实现个性化的网站定制,开发出功能强大的网站。

基本模式:

Flask的基本模式为在程序里将一个视图函数分配给一个URL,每当用户访问这个URL时,系统就会执行给该URL分配好的视图函数,获取函数的返回值并将其显示到浏览器上,其工作过程见图。

1、简单,Flask的路由以及路由函数由修饰器设定,开发人员不需要借助其他文件匹配;2、配置灵活,有多种方法配置,不同环境的配置也非常方便;环境部署简单,Flask运行不需要借助其他任何软件,只需要安装了Python的IDE,在命令行运行即可。只需要在Python中导入相应包即可满足所有需求;3、入门简单,通过官方指南便可以清楚的了解Flask的运行流程;4、低耦合,Flask可以兼容多种数据库、模板。

更多详情: flask开发文档

如何安装Flask?

在mind+的python模式下:点击“库管理”→"pip模式"下:

输入:pip install Flask

3、安装pinpong

pinpong库是一套控制开源硬件主控板的Python库,基于Firmata协议并兼容MicroPython语法,5分钟即可让你上手使用Python控制开源硬件。

借助于pinpong库,直接用Python代码就能给各种常见的开源硬件编程。其原理是给开源硬件烧录一个特定的固件,使开源硬件可以通过串口与电脑通讯,执行各种命令。

pinpong库的名称由“Pin”和“Pong”组成,“Pin”指引脚,“PinPong”为“乒乓球”的谐音,指信号的往复。

pinpong库的设计,是为了让开发者在开发过程中不用被繁杂的硬件型号束缚,而将重点转移到软件的实现。哪怕程序编写初期用 Arduino 开发,部署时改成了 掌控板 ,只要修改一下硬件的参数就能正常运行,实现了“一次编写处处运行”。

当前PinPong库正在快速更新中,已支持Arduino系列uno、leonardo、mega2560,ESP32系列掌控板(handpy)以及 micro:bit 板,传感器支持50+,其他主控板及更多扩展库将逐步支持。

更多详情: pinpong开发手册

如何安装pinpong?

在mind+的python模式下:点击“库管理”→"推荐库"→"硬件控制"→"pinpong"点击安装即可

4、硬件清单

Step 2: 拷贝 pyecharts 模板

将 pyecharts 模板,位于 “C:\Users\83731\Documents\mindplus-py\environment\Python3.6.5-64\Lib\site-packages\pyecharts\render\templates”拷贝至刚新建的 templates 文件夹

(ps:这里的index.html文件是我自己新建的,后面会讲到)

Flask 前后端分离

Step 3: 新建一个 HTML 文件

新建 HTML 文件保存位于项目根目录的 templates 文件夹,这里以如下 index.html 为例. 主要用到了 jquery 和 pyecharts 管理的 echarts.min.js 依赖!后面用到水球图和词云需要用到echarts-liquidfill.min.js,echarts-wordcloud.min.js

这里你可能需要一点HTML,CSS,javascript等前端的知识,有兴趣的老师可以去 w3school 了解一下!(PS:本人也是小白一个,所设计的界面很low,希望大神勿喷!)

前端主动向后端进行数据刷新

定时刷新的核心在于 HTML 的 setInterval 方法。

<!DOCTYPE html>
    <meta charset="UTF-8">
    <title>智能家居</title>
        <script type="text/javascript" src="https://assets.pyecharts.org/assets/echarts.min.js"></script>
    <script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.0.0/jquery.min.js"></script>
    <script type="text/javascript" src="https://assets.pyecharts.org/assets/echarts-liquidfill.min.js"></script>
        <script type="text/javascript" src="https://assets.pyecharts.org/assets/echarts-wordcloud.min.js"></script>
        <style>
                h1{font-family:"隶书";color:#9AB3F5;font-size:50px;margin-align:center;line-height:80px;}
                div{box-shadow:0 10px 20px rgba(191, 216, 184,0.19), 0 6px 6px rgba(191, 216, 184,0.23);border-radius:5px;background:#E8F6EF;position:relative; }
                #liquid{width:800px; height:400px;margin-left:50px; margin-top:20px;float: left;}
                #pressure{width:500px; height:400px;margin-left:40px; margin-top:20px; float: left;}
                #altitude{width:500px; height:400px;margin-left:40px; margin-top:20px;float: left;}
                #line{width:800px; height:400px;margin-top:20px;margin-left:50px;float: left;}
                #bar{width:500px; height:400px;margin-left:40px;margin-top:20px;float: left;}
                #wordcloud{width:500px; height:400px;margin-left:40px;margin-top:20px;float: left;}
                .ttop{width:100%;height:90px;text-align:center; margin-top:-20px;background:#6F69AC;}
</style>
</head>
        <div class="ttop" style="">
                <h1 > 基于Pyecharts + Flask + Pingpong 智能家居数字大屏系统</h1>
                <div id="liquid" ></div>
                <div id="pressure"></div>
                <div id="altitude"></div>
                <div id="line"></div>
                <div id="bar"> </div>
                <div id="wordcloud"> </div>
    <script>
        var liquid = echarts.init(document.getElementById('liquid'), 'white', {renderer: 'canvas'});
            function () {
                fetchliquidData(liquid);
                setInterval(fetchliquidData, 2000);
        function fetchliquidData() {
            $.ajax({
                type: "GET",
                url: "http://127.0.0.1:5000/liquidChart",
                                dataType:'json',
                                success: function (result) {
                                        var jsonResult = JSON.stringify(result);
                                        var jsonResult =  JSON.parse(jsonResult,function(key,value){
                                                if(key === "formatter"){
                                                        console.log(value);
                                                        return eval('('+value+')');
                                                }else{
                                                        return value;
                                        console.log(jsonResult);        
                                        liquid.setOption(jsonResult);
    </script>
    <script>
        var pressure = echarts.init(document.getElementById('pressure'), 'white', {renderer: 'canvas'});
            function () {
                fetchpressureData(pressure);
                setInterval(fetchpressureData, 2000);
        function fetchpressureData() {
            $.ajax({
                type: "GET",
                url: "http://127.0.0.1:5000/pressureChart",
                                dataType:'json',
                                success: function (result) {
                                        pressure.setOption(result);
    </script>
    <script>
        var altitude = echarts.init(document.getElementById('altitude'), 'white', {renderer: 'canvas'});
            function () {
                fetchaltitudeData(altitude);
                setInterval(fetchaltitudeData, 2000);
        function fetchaltitudeData() {
            $.ajax({
                type: "GET",
                url: "http://127.0.0.1:5000/altitudeChart",
                                dataType:'json',
                                success: function (result) {
                                        altitude.setOption(result);
    </script>
    <script>
        var line = echarts.init(document.getElementById('line'), 'white', {renderer: 'canvas'});
        var old_data = [];
            function () {
                fetchlineData(line);
                setInterval(getDynamicData, 2000);
        function fetchlineData() {
            $.ajax({
                type: "GET",
                url: "http://127.0.0.1:5000/lineChart",
                dataType: "json",
                success: function (result) {
                    line.setOption(result);
                    old_data = line.getOption().series[0].data;
        function getDynamicData() {
            $.ajax({
                type: "GET",
                url: "http://127.0.0.1:5000/lineDynamicData",
                dataType: "json",
                success: function (result) {
                    old_data.push([result.name, result.value]);
                    line.setOption({
                        series: [{data: old_data}]
    </script>
        <script>
        var bar = echarts.init(document.getElementById('bar'), 'white', {renderer: 'canvas'});
            function () {
                fetchbarData(bar);
                setInterval(fetchbarData, 2000);
        function fetchbarData() {
            $.ajax({
                type: "GET",
                url: "http://127.0.0.1:5000/barChart",
                                dataType:'json',
                                success: function (result) {
                                        bar.setOption(result);
    </script>
        <script>
        var wordcloud = echarts.init(document.getElementById('wordcloud'), 'white', {renderer: 'canvas'});
            function () {
                fetchwordcloudData(wordcloud);
                setInterval(fetchwordcloudData, 2000);
        function fetchwordcloudData() {
            $.ajax({
                type: "GET",
                url: "http://127.0.0.1:5000/wordcloudChart",
                                dataType:'json',
                                success: function (result) {
                                        wordcloud.setOption(result);
    </script>
</body>
</html>

Step 4: 新建app.py文件

请将下面的代码保存为 app.py 文件并移至项目的根目录下。

该程序主要用pingpong来获取传感器的数据,然后将数据放到pyecharts的chart中。然后通过falsk web框架每个两秒将数据发送到前端!浏览器输入: http://127.0.0.1:5000/。进行页面显示。主要用到了get请求来获取数据

from random import randrange # 导入Flask  相关库文件 from flask import Flask, render_template from flask.json import jsonify # 导入pyecharts 相关库文件 from pyecharts import options as opts from pyecharts.charts import Grid, Liquid,Gauge,Line,Pie,Bar,WordCloud from pyecharts.faker import Faker from pyecharts.commons.utils import JsCode from pyecharts.globals import ThemeType # 导入pinpong库相关文件 from pinpong.board import Board,Pin from pinpong.libs.dfrobot_bme280 import BME280 import time Board("uno").begin() # BME280 初始化 bme = BME280() app = Flask(__name__, static_folder="templates") date=[0,0,0,0] # 创建水球图 def create_liquid_charts(temp,humi) ->Liquid:     l1 = (     Liquid()     .add("湿度", # 系列名称         [humi], # 系列数值     center=["48%", "50%"], # 设置x,y坐标值     label_opts=opts.LabelOpts( # 标签配置项             font_size=35,  # 标签大小              position="inside",     .set_global_opts(title_opts=opts.TitleOpts(title="温湿度电量水球图")) # 提示框组件配置项     l2 = (     Liquid()     .add(         "温度",         [temp],         center=["18%", "50%"],         color=["#FFA500"],         label_opts=opts.LabelOpts(             font_size=35,             formatter=JsCode(                 """function (param) {                     return (Math.floor(param.value * 10000) / 100) + '℃';             position="inside",     Liquid()     .add("电量", [0.8],     center=["78%", "50%"],     color=["#00FA9A"], # 水球图波浪颜色     label_opts=opts.LabelOpts(             font_size=35,              position="inside", # 通过grid 并行多图将三个水球合并在一张图上     grid = Grid().add(l1, grid_opts=opts.GridOpts()).add(l2, grid_opts=opts.GridOpts()).add(l3, grid_opts=opts.GridOpts())     return grid # 创建仪表盘 def creat_pressure_chart(press) -> Gauge:     c = (         Gauge()         .add("",         [("压强", press)],         min_=['0'], # 最小值         max_=['2000'], # 最大值         split_number=5,         axisline_opts=opts.AxisLineOpts( # 设置仪表盘颜色及宽度             linestyle_opts=opts.LineStyleOpts(                 color=[(0.3, "#67e0e3"), (0.7, "#37a2da"), (1, "#fd666d")], width=30         detail_label_opts=opts.LabelOpts(formatter="{value}  Pa"),) # 格式         .set_global_opts(title_opts=opts.TitleOpts(title="压强仪表盘"))     return c # 创建海拔仪表盘 def creat_altitude_chart(alti) -> Gauge:     c1 =(         Gauge()         .add("",         [("海拔", alti)],         min_=['0'], # 最小值         max_=['1000'], # 最大值         split_number=5,         axisline_opts=opts.AxisLineOpts( # 设置仪表盘颜色及宽度             linestyle_opts=opts.LineStyleOpts(                 color=[(0.3, "#F3EAC2"), (0.7, "#F5B461"), (1, "#EC524B")], width=30         detail_label_opts=opts.LabelOpts(formatter="{value}  M"),) # 格式         .set_global_opts(title_opts=opts.TitleOpts(title="海拔仪表盘"))     return c1 # 创建折现图   def line_base() -> Line:     line = (         Line()         .add_xaxis(["{}".format(i) for i in range(10)])         .add_yaxis(             series_name="",             y_axis=[randrange(20, 35) for _ in range(10)],             is_smooth=True,             label_opts=opts.LabelOpts(is_show=False),         .set_global_opts(             title_opts=opts.TitleOpts(title="温度动态数据显示"),             xaxis_opts=opts.AxisOpts(type_="value"),             yaxis_opts=opts.AxisOpts(type_="value"),     return line # 创建主创图 def creat_bar_chart(temp,humi,press,alti) -> Bar:     c = (         Bar(init_opts=opts.InitOpts(theme=ThemeType.LIGHT))         .add_xaxis(["温度","湿度","压强","海拔"])         .add_yaxis("小明家", [temp,humi,press,alti])         .set_global_opts(title_opts=opts.TitleOpts(title="BME280数据显示"))     return c data = [     ("hockel", "2004"),     ("智能家居", "1500"),     ("少儿编程", "777"),     ("人工智能", "666"),     ("python", "200"),     ("mind+", "555"),     ("Erised", "1204"),     ("温度", "50"),     ("湿度", "40"),     ("压强", "21"),     ("海拔", "30"),     ("BME280", "21"),     ("pyecharts", "99"),     ("arduino", "50"),     ("flask", "80"),     ("html", "60"),     ("css", "20"),     ("js", "70"),     ("pinpong", "120"), # 创建词云 def creat_wordcloud_chart() -> WordCloud:     c = (     WordCloud()     .add(series_name="所用技术", data_pair=data, word_size_range=[6, 66])     .set_global_opts(         title_opts=opts.TitleOpts(             title="所用技术", title_textstyle_opts=opts.TextStyleOpts(font_size=23)         tooltip_opts=opts.TooltipOpts(is_show=True),     return c @app.route("/") def index():     return render_template("index.html") @app.route("/liquidChart") def get_liquid_chart():     date[0] =  bme.temp_c()     date[1] =  bme.humidity()     date[2] =  bme.press_pa()     date[3] =  bme.cal_altitudu()     temp = date[0] / 100     humi = date[1] / 100     c = create_liquid_charts(temp,humi)     return c.dump_options_with_quotes() # 压强仪表盘 @app.route("/pressureChart") def get_pressure_chart():     press = date[2] / 100     c = creat_pressure_chart(press)     return c.dump_options_with_quotes() # 海拔仪表盘 @app.route("/altitudeChart") def get_altitude_chart():     alti =  date[3]     c = creat_altitude_chart(alti)     return c.dump_options_with_quotes() # 动态图 @app.route("/lineChart") def get_line_chart():     c = line_base()     return c.dump_options_with_quotes() idx = 9 @app.route("/lineDynamicData") def update_line_data():     global idx     idx = idx + 1     return jsonify({"name": idx, "value": date[0]}) # 柱状图 @app.route("/barChart") def get_bar_chart():     c = creat_bar_chart(date[0],date[1],date[2]/100,date[3])     return c.dump_options_with_quotes() @app.route("/wordcloudChart") def get_wordcloud_chart():     c = creat_wordcloud_chart()     return c.dump_options_with_quotes() if __name__ == "__main__":     app.run()

解决方法:

找到pyecharts的安装目录(右击右侧项目:打开文件所在位置即可找到):

C:\Users\83731\Documents\mindplus-py\environment\Python3.6.5-64\Lib\site-packages\

然后修改pyecharts\charts\basic_charts\chart.py文件

2、pyecharts中的水球图不显示问题:

在遇到这个问题之后,了解一下echarts,才知道echarts-liquidfill是第三方插件,需要单独导入

需要在index.html文件中标签内加入:

<script type="text/javascript" src="https://assets.pyecharts.org/assets/echarts-liquidfill.min.js"></script>

3、水球图在进行数据精度显示是时:单位不能显示!

在看了pyecharts文档时有一处写到:

注: 目前由于 json 数据类型的问题,无法将 pyecharts 中的 JSCode 类型的数据转换成 json 数据格式返回到前端页面中使用。因此在使用前后端分离的情况下尽量避免使用 JSCode 进行画图。

l2 = (
    Liquid()
    .add(
        "温度",
        [0.3254],
        center=["18%", "50%"],
        color=["#FFA500"],
        label_opts=opts.LabelOpts(
            font_size=35,
            formatter=JsCode(
                """function (param) {
                    return (Math.floor(param.value * 10000) / 100) + '℃';
            position="inside",

我这这里jscode返回的对象是str:str! 然而我们需要调用jscode的函数!我们需要在html的文档中进行数据处理:将str:str 转换成 str:function().找到我们调用的liquid的script标签进行如下更改!

 function fetchliquidData() {
            $.ajax({
                type: "GET",
                url: "http://127.0.0.1:5000/liquidChart",
                                dataType:'json',
                                success: function (result) {
                                        var jsonResult = JSON.stringify(result);
                                        jsonResult =  JSON.parse(jsonResult,function(key,value){
                                                if(key === "formatter"){
                                                        console.log(value);
                                                        return eval('('+value+')');
                                                }else{
                                                        return value;
                                        console.log(jsonResult);        
                                        liquid.setOption(jsonResult);

4.用grid组件无法将liquid和gauge并列合并在同一图上!

使用grid时,一般情况下,永远不要先给grid加入一个没有x y轴的图,比如饼图、仪表盘、地图等等。

如果你想加的,可以参考这篇文章:pyecharts丨页面布局工具——grid注意事项和overlap的使用

整个项目做下来!被Flask的前后端分离数据显示问题搞得崩溃!主要还是因为自己的前端知识有点薄弱。为此自己恶补了一晚的前端的html,css,js等知识!对falsk web框架和pyecharts有了进一步的了解!屏幕前的你,有没有学吐了呢?反正我是秃了!

更多教程欢迎关注个人博客:www.hockel.club

项目源码请关注微信公众号:跟着hockel玩科创

​                                                                回复:“pyecharts”即可获得