前言

本次小项目是学弟提出的,可视化一般都涉及Echart作图,本次使用Flask框架快速搭建后端,使用Echart作为画图工具

项目结构

+---static                    # 静态资源目录
|   +---css                   # CSS文件目录
|   +---fonts                 # 字体文件目录
|   +---img                   # 图片文件目录
|   \---js                    # JavaScript文件目录
+---templates                 # 模板文件目录
+---weather_data              # 天气数据目录
│       app.py                # 应用程序主文件
│       clean.py              # 数据清洗文件
│       ua_info.py            # UA信息文件
│       weather_spider.py     # 天气爬虫文件

最后效果图

首页图

首页图

具体城市页

具体城市

后端准备工作

模拟随机UA

ua_list = [
    'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon 2.0',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
    'User-Agent:Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11',
    'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
    'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)',
    'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
    'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0',
    'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1',
    'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
]

爬虫代码

选取的weather.com.cn的数据源进行数据爬取

# spider.py
import requests
from bs4 import BeautifulSoup
import csv
import json
from ua_info import ua_list  # 使用自定义的ua池
import random
import time
import os
import clean


class WeatherSpider(object):
    def __init__(self):
        # 初始化url属性
        self.url1 = 'http://www.weather.com.cn/weather/{}'
        self.url2 = 'http://www.weather.com.cn/weather15d/{}'
        self.url3 = 'https://weather.cma.cn/web/weather/{}'
        # 地区id
        self.weather_id_14 = {
            "哈尔滨": 101050101,
            "齐齐哈尔": 101050201,
            "牡丹江": 101050301,
            "佳木斯": 101050401,
            "绥化": 101050501,
            "黑河": 101050601,
            "大兴安岭": 101050701,
            "伊春": 101050801,
            "大庆": 101050901,
            "鸡西": 101051101,
            "鹤岗": 101051201,
            "双鸭山": 101051301,
            "七台河": 101051002,
            "阿城": 101050104,
            "尚志": 101050111,
            "五常": 101050112
        }

        self.weather_id_mw = {
            "哈尔滨": 50953,
            "齐齐哈尔": 50745,
            "牡丹江": 54094,
            "佳木斯": 50873,
            "大庆": 50850,
            "鸡西": 50978,
            "鹤岗": 50775,
            "双鸭山": 50884,
            "伊春": 50774,
            "七台河": 50971,
            "黑河": 50468,
            "绥化": 50853
        }

        self.spider_id = 1

    def get_html(self, url):
        # 请求获得网页内容
        try:
            headers = {'User-Agent': random.choice(ua_list)}
            r = requests.get(url, headers=headers, timeout=30)
            r.raise_for_status()
            # 判断返回的Response类型状态是不是200,如果是200,将表示返回的内容是正确的,如果不是200,会产生一个HttpError的异常
            r.encoding = r.apparent_encoding
            print('访问成功--', self.spider_id)
            self.spider_id += 1
            return r.text
        except:
            print('访问错误')
            return ''

    def get_content_7d(self, html):
        # 处理得到有用信息保存数据文件
        bs = BeautifulSoup(html, 'html.parser')  # 创建BeautifulSoup对象
        body = bs.body

        # 处理当天的数据
        data_today = body.find_all('div', {'class': 'left-div'})
        text = data_today[2].find('script').string
        text = text[text.index('=') + 1:-2]  # 移除var,将其变为json数据
        jd = json.loads(text)
        today = jd['od']['od2']  # 找到当天的数据
        final_day = []  # 初始化一个列表保存数据
        count = 0
        for i in today:
            temp = []  # 临时存放数据
            if count <= 23 and count != 0: # today数组内的第一个数据无用跳过
                temp.append(i['od21'])  # 添加时间
                temp.append(i['od22'])  # 添加当前时刻温度
                temp.append(i['od24'])  # 添加当前时刻风力方向
                temp.append(i['od25'])  # 添加当前时刻风级
                temp.append(i['od26'])  # 添加当前时刻降水量
                temp.append(i['od27'])  # 添加当前时刻相对湿度
                temp.append(i['od28'])  # 添加当前时刻空气质量
                # print(temp)
                final_day.append(temp)
            count = count + 1

        # 处理7天数据
        data_7d = body.find('div', {'id': '7d'})  # 找到div标签且id = 7d
        ul = data_7d.find('ul')  # 找到所有的ul标签
        li = ul.find_all('li')  # 找到所有的li标签
        final = []  # 初始化一个列表保存数据
        i = 0  # 控制爬取的天数
        for day in li:  # 遍历找到的每一个li
            if 7 > i > 0:
                temp = []  # 临时存放数据
                date = day.find('h1').string  # 得到日期
                date = date[0:date.index('日')]  # 取出日期号
                temp.append(date)
                inf = day.find_all('p')  # 找出li下面的p标签,提取第一个p标签的值,即天气
                temp.append(inf[0].string)

                tem_low = inf[1].find('i').string  # 找到最低气温
                temp.append(tem_low[:-1])

                if inf[1].find('span') is None:  # 天气预报可能没有最高气温
                    tem_high = None
                else:
                    tem_high = inf[1].find('span').string  # 找到最高气温
                if tem_high[-1] == '℃':
                    temp.append(tem_high[:-1])
                else:
                    temp.append(tem_high)

                wind = inf[2].find_all('span')  # 找到风向
                for j in wind:
                    temp.append(j['title'])

                wind_scale = inf[2].find('i').string  # 找到风级
                index1 = wind_scale.index('级')
                temp.append(int(wind_scale[index1 - 1:index1]))
                final.append(temp)
            i = i + 1
        return final_day, final
        # print(final)

    def get_content_14d(self, html):
        # 处理得到有用信息保存数据文件
        bs = BeautifulSoup(html, "html.parser")  # 创建BeautifulSoup对象
        body = bs.body
        data = body.find('div', {'id': '15d'})  # 找到div标签且id = 15d
        ul = data.find('ul')  # 找到所有的ul标签
        li = ul.find_all('li')  # 找到所有的li标签
        final = []  # 初始化一个列表保存数据
        i = 0  # 控制爬取的天数
        for day in li:  # 遍历找到的每一个li
            if i < 8:
                temp = []  # 临时存放每天的数据
                date = day.find('span', {'class': 'time'}).string  # 得到日期
                date = date[date.index('(') + 1:-2]  # 取出日期号
                temp.append(date)
                weather = day.find('span', {'class': 'wea'}).string  # 找到天气
                temp.append(weather)
                tem = day.find('span', {'class': 'tem'}).text  # 找到温度
                temp.append(tem[tem.index('/') + 1:-1])  # 找到最低气温
                temp.append(tem[:tem.index('/') - 1])  # 找到最高气温
                wind = day.find('span', {'class': 'wind'}).string  # 找到风向
                if '转' in wind:  # 如果有风向变化
                    temp.append(wind[:wind.index('转')])
                    temp.append(wind[wind.index('转') + 1:])
                else:  # 如果没有风向变化,前后风向一致
                    temp.append(wind)
                    temp.append(wind)
                wind_scale = day.find('span', {'class': 'wind1'}).string  # 找到风级
                index1 = wind_scale.index('级')
                temp.append(int(wind_scale[index1 - 1:index1]))
                final.append(temp)
        return final

    def get_html_mw(self, name, html):
        # 处理得到有用信息保存数据文件
        bs = BeautifulSoup(html, "html.parser")  # 创建BeautifulSoup对象
        body = bs.body
        final = [name]
        data_max_all = body.find_all('div', {'class': 'high'})
        data_max = data_max_all[0].string
        data_max = data_max[data_max.index('℃') - 2:data_max.index('℃')].strip()
        data_min_all = body.find_all('div', {'class': 'low'})
        data_min = data_min_all[0].string
        data_min = data_min[data_min.index('℃') - 2:data_min.index('℃')].strip()
        final.append(data_min)
        final.append(data_max)
        return final
        
    #保存本地CSV文件
    def write_to_csv(self, file_name, data, day):
        if not os.path.exists('./weather_data'):  # 判断是否存在文件夹
            os.mkdir('./weather_data')  # 添加文件夹
        path = os.path.join('./weather_data', file_name)  # 拼接相对路径
        # 保存为CSV
        with open(path, 'w', errors='ignore', newline='') as f:
            if day == 14:
                header = ['日期', '天气', '最低气温', '最高气温', '风向1', '风向2', '风级']
            else:
                header = ['小时', '温度', '风力方向', '风级', '降水量', '相对湿度', '空气质量']
            f_csv = csv.writer(f)
            f_csv.writerow(header)
            f_csv.writerows(data)

    def run(self):
        # 入口函数
        print("Weather test")
        for key, value in self.weather_id_14.items():
            url_id = str(value) + '.shtml'
            url1 = self.url1.format(url_id)
            url2 = self.url2.format(url_id)
            html1 = self.get_html(url1)
            data1, data1_7 = self.get_content_7d(html1)  # 获得1-7天和当天的数据
            html2 = self.get_html(url2)
            data8_14 = self.get_content_14d(html2)  # 获得8-14天数据
            date14 = data1_7 + data8_14
            name1 = key + '1.csv'
            name2 = key + '14.csv'
            self.write_to_csv(name1, data1, 1)  # 保存为CSV
            self.write_to_csv(name2, date14, 14)
            # 每爬取一个页面随机休眠1-2秒钟的时间
            time.sleep(random.randint(1, 2))

        with open('./weather_data\\mw.csv', 'w', errors='ignore', newline='') as f:
            f_csv = csv.writer(f)
            header = ['城市', '最低温', '最高温']
            f_csv.writerow(header)
            for key, value in self.weather_id_mw.items():
                url_id = str(value) + '.html'
                url3 = self.url3.format(url_id)
                html3 = self.get_html(url3)
                f_csv.writerow(self.get_html_mw(key, html3))
                # 每爬取一个页面随机休眠1-2秒钟的时间
                time.sleep(random.randint(1, 2))


if __name__ == '__main__':
    start = time.time()
    spider = WeatherSpider()  # 实例化一个对象spider
    spider.run()  # 调用入口函数
    clean.run()
    end = time.time()
    # 查看程序执行时间
    print('执行时间:%.2f' % (end - start))  # 爬虫执行时间

清空本地数据代码

import pandas as pd

path = './weather_data\\{}'
city = ['哈尔滨', '黑河', '鸡西', '七台河', '绥化', '牡丹江', '大兴安岭', '佳木斯', '双鸭山', '五常', '齐齐哈尔', '尚志', '阿城', '大庆', '伊春', '鹤岗']


def clean_data(path):
    data = pd.read_csv(path, encoding='gbk', header=0)
    data = data.fillna(axis=0, method='ffill')
    data = data.fillna(axis=0, method='bfill')
    data.to_csv(path, encoding='gbk', index=0)


def run():
    print('开始清洗')
    for index in city:
        path_1d = path.format(index + '1.csv')
        path_14d = path.format(index + '14.csv')
        clean_data(path_1d)
        clean_data(path_14d)


if __name__ == '__main__':
    run()

前端准备工作

本次获取的是黑龙江的数据,前端首页设计了一张黑龙江省全省地形图,所以需要获取到geo数据本次使用了DataV获取GEOJson数据 存放在静态文件(static/js)中进行引用

header页

<!DOCTYPE html>
<html lang="en">
<head>
<head>
    <meta charset="utf-8">
    <title>天气可视化分析</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="description" content=""/>
    <meta name="author" content=""/>
    <script src="../static/js/echarts.min.js"></script>
    <!-- css -->
    <link href="../static/css/bootstrap.min.css" rel="stylesheet"/>
    <link href="../static/css/fancybox/jquery.fancybox.css" rel="stylesheet">
    <link href="../static/css/flexslider.css" rel="stylesheet"/>
    <link href="../static/css/style.css" rel="stylesheet"/>
</head>
</head>
<body>
    <!-- start header -->
    <header>
        <div class="navbar navbar-default navbar-static-top">
            <div class="container">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse"
                            data-target=".navbar-collapse">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                    <a class="navbar-brand" href="index">天气数据爬取及可视化分析</a>
                </div>
                <div class="navbar-collapse collapse ">
                    <ul class="nav navbar-nav">
                        <li><a href="/index">首页</a></li>
                        <li class="dropdown">
                            <a href="#" data-toggle="dropdown" class="dropdown-toggle">城市<b
                                    class="caret"></b></a>
                            <ul class="dropdown-menu">
                                <li><a href="/weather/haerbin">哈尔滨</a></li>
                                <li><a href="/weather/qiqihaer">齐齐哈尔</a></li>
                                <li><a href="/weather/mudanjiang">牡丹江</a></li>
                                <li><a href="/weather/jiamusi">佳木斯</a></li>
                                <li><a href="/weather/daqing">大庆</a></li>
                                <li><a href="/weather/jixi">鸡西</a></li>
                                <li><a href="/weather/hegang">鹤岗</a></li>
                                <li><a href="/weather/shuangyashan">双鸭山</a></li>
                                <li><a href="/weather/yichun">伊春</a></li>
                                <li><a href="/weather/qitaihe">七台河</a></li>
                                <li><a href="/weather/heihe">黑河</a></li>
                                <li><a href="/weather/suihua">绥化</a></li>
                                <li><a href="/weather/daxinganling">大兴安岭</a></li>

                            </ul>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    </header>
    <!-- end header -->
</body>
</html>

footer页

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 <footer>
        <div class="container">
            <div id="sub-footer">
                <div class="container">
                    <div class="row">
                        <div class="col-lg-6">
                            <div class="copyright">
                                <p>
                                    xxx
                                </p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </footer>
</body>
</html>

首页

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>天气可视化分析</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="description" content=""/>
    <meta name="author" content=""/>
    <script src="../static/js/echarts.min.js"></script>
     <!--  黑龙江geoJson数据  -->
    <script src="../static/js/geoJson.js"></script>
    <!-- css -->
    <link href="../static/css/bootstrap.min.css" rel="stylesheet"/>
    <link href="../static/css/fancybox/jquery.fancybox.css" rel="stylesheet">
    <link href="../static/css/flexslider.css" rel="stylesheet"/>
    <link href="../static/css/style.css" rel="stylesheet"/>
</head>
<body>
<div id="wrapper" class="home-page">
    <!-- 导入header.html -->
    {% include 'header.html' %}
    <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
    <div id="visualMap" style="height: 600px;width: 1300px;margin: 0 auto"></div>
    <div id="container" style="height: 600px;width: 1300px;margin: 0 auto"></div>

    <!-- 导入footer.html -->
    {% include 'footer.html' %}
</div>
<a href="#" class="scrollup"><i class="fa fa-angle-up active"></i></a>
<!-- javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->

<script type="text/javascript">
    var dom = document.getElementById('container');
    var myChart = echarts.init(dom, null, {
        renderer: 'canvas',
        useDirtyRect: false
    });
    var app = {};

    var option;

    const posList = [
        'left',
        'right',
        'top',
        'bottom',
        'inside',
        'insideTop',
        'insideLeft',
        'insideRight',
        'insideBottom',
        'insideTopLeft',
        'insideTopRight',
        'insideBottomLeft',
        'insideBottomRight'
    ];
    app.configParameters = {
        rotate: {
            min: -90,
            max: 90
        },
        align: {
            options: {
                left: 'left',
                center: 'center',
                right: 'right'
            }
        },
        verticalAlign: {
            options: {
                top: 'top',
                middle: 'middle',
                bottom: 'bottom'
            }
        },
        position: {
            options: posList.reduce(function (map, pos) {
                map[pos] = pos;
                return map;
            }, {})
        },
        distance: {
            min: 0,
            max: 100
        }
    };
    app.config = {
        rotate: 90,
        align: 'left',
        verticalAlign: 'middle',
        position: 'insideBottom',
        distance: 15,
        onChange: function () {
            const labelOption = {
                rotate: app.config.rotate,
                align: app.config.align,
                verticalAlign: app.config.verticalAlign,
                position: app.config.position,
                distance: app.config.distance
            };
            myChart.setOption({
                series: [
                    {
                        label: labelOption
                    },
                    {
                        label: labelOption
                    },
                    {
                        label: labelOption
                    },
                    {
                        label: labelOption
                    }
                ]
            });
        }
    };
    const labelOption = {
        show: true,
        position: app.config.position,
        distance: app.config.distance,
        align: app.config.align,
        verticalAlign: app.config.verticalAlign,
        rotate: app.config.rotate,
        formatter: '{c}  {name|{a}}',
        fontSize: 16,
        rich: {
            name: {}
        }
    };
    option = {
        title: {
            text: '                             各市气温对比'
        },
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                type: 'shadow'
            }
        },
        legend: {
            data: ['最低温', '最高温']
        },
        toolbox: {
            show: true,
            orient: 'vertical',
            left: 'right',
            top: 'center',
            feature: {
                mark: {show: true},
                dataView: {show: true, readOnly: false},
                magicType: {show: true, type: ['line', 'bar', 'stack']},
                restore: {show: true},
                saveAsImage: {show: true}
            }
        },
        xAxis: [
            {
                type: 'category',
                axisTick: {show: false},
                data: ['哈尔滨', '齐齐哈尔', '牡丹江', '佳木斯', '大庆', '鸡西', '鹤岗', '双鸭山', '伊春', '七台河', '黑河', '绥化']

            }
        ],
        yAxis: [
            {
                type: 'value'
            }
        ],
        series: [
            {
                name: '最低温',
                type: 'bar',
                barGap: 0,
                label: labelOption,
                showBackground: true,
                backgroundStyle: {
                    color: 'rgba(180, 180, 180, 0.2)'
                },
                emphasis: {
                    focus: 'series'
                },
                data: {{ data_min }}
            },
            {
                name: '最高温',
                type: 'bar',
                label: labelOption,
                showBackground: true,
                backgroundStyle: {
                    color: 'rgba(180, 180, 180, 0.2)'
                },
                emphasis: {
                    focus: 'series'
                },
                data: {{ data_max }}
            }
        ]
    };


    if (option && typeof option === 'object') {
        myChart.setOption(option);
    }

    echarts.registerMap('哈尔滨', geoJson);
    // 初始化echarts实例
    var mapChart = echarts.init(document.getElementById('visualMap'));
    //测试数据
    var temperatureData = [
        {name: '哈尔滨市', value: -20, maxTemp: -10, minTemp: -10},
        {name: '齐齐哈尔市', value: 24, maxTemp: 29, minTemp: 19},
        {name: '牡丹江市', value: 23, maxTemp: 28, minTemp: 18},
        {name: '佳木斯市', value: 26, maxTemp: 31, minTemp: 21},
        {name: '大庆市', value: 27, maxTemp: 32, minTemp: 22},
        {name: '鸡西市', value: 22, maxTemp: 27, minTemp: 17},
        {name: '鹤岗市', value: 21, maxTemp: 26, minTemp: 16},
        {name: '双鸭山市', value: 22, maxTemp: 27, minTemp: 17},
        {name: '伊春市', value: 20, maxTemp: 25, minTemp: 15},
        {name: '七台河市', value: 19, maxTemp: 24, minTemp: 14},
        {name: '绥化市', value: 24, maxTemp: 29, minTemp: 19},
        {name: '黑河市', value: 23, maxTemp: 28, minTemp: 18},
        {name: '大兴安岭地区', value: 18, maxTemp: 23, minTemp: 13}
    ];


    // 配置项
    var mapOption = {
        tooltip: {
            trigger: 'item',
            formatter: function (params) {
                if (params.data) {
                    return params.name + "<br/>最高温:" + params.data.maxTemp + "°C<br/>最低温:" + params.data.minTemp + "°C";
                } else {
                    return params.name;
                }
            }
        },
        visualMap: {
            min: -20,
            max: 40,
            calculable: true,
            inRange: {
                color: ['#50a3ba', '#eac736', '#d94e5d']
            }
        },
        series: [
            {
                type: 'map',
                map: '哈尔滨', // 地图名称,对应到echarts.registerMap()中的地图名称
                data: {{temperatureData|tojson|safe}}, // 各地区温度数据使用引用后端数据,
                label: {
                    show: true
                },


            }
        ]
    };

    // 使用刚指定的配置项和数据显示图表。
    mapChart.setOption(mapOption);

    window.addEventListener('resize', mapChart.resize);
    window.addEventListener('resize', myChart.resize);
</script>

<script src="../static/js/jquery.js"></script>
<script src="../static/js/jquery.easing.1.3.js"></script>
<script src="../static/js/bootstrap.min.js"></script>
<script src="../static/js/jquery.fancybox.pack.js"></script>
<script src="../static/js/jquery.fancybox-media.js"></script>
<script src="../static/js/jquery.flexslider.js"></script>
<script src="../static/js/animate.js"></script>
<!-- Vendor Scripts -->
<script src="../static/js/modernizr.custom.js"></script>
<script src="../static/js/jquery.isotope.min.js"></script>
<script src="../static/js/jquery.magnific-popup.min.js"></script>
<script src="../static/js/animate.js"></script>
<script src="../static/js/custom.js"></script>
</body>
</html>

具体城市页

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>天气可视化分析</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="description" content=""/>
    <meta name="author" content=""/>
    <script src="../static/js/echarts.min.js"></script>
    <!-- css -->
    <link href="../static/css/bootstrap.min.css" rel="stylesheet"/>
    <link href="../static/css/fancybox/jquery.fancybox.css" rel="stylesheet">
    <link href="../static/css/flexslider.css" rel="stylesheet"/>
    <link href="../static/css/style.css" rel="stylesheet"/>
</head>
<body>
<div id="wrapper" class="home-page">
    <!-- 导入header.html -->
    {% include 'header.html' %}

    <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
    <div id="every_hour" style="width: 1300px;height:600px;margin: 0 auto;"></div>
    <br><br>
    <div id="shidu_zhiliang" style="width: 1300px;height:600px;margin: 0 auto;"></div>
    <br><br>
    <p style="text-align: center">{{ city_name }}每小时风力,风向,降水量对比</p>
    <table class="table table-striped" style="width: 90%;text-align: center;margin: 0 auto;">
        <tr>
            <td>时间</td>
            <td>风力方向</td>
            <td>风级</td>
            <td>降水量</td>
        </tr>
        {% for index in range(0, 24) %}
            <tr>
                <td>{{ time_1d[index] }}</td>
                <td>{{ fangxiang_1d[index] }}</td>
                <td>{{ fengji_1d[index] }}</td>
                <td>{{ jiangshui_1d[index] }}</td>
            </tr>
        {% endfor %}
    </table>
    <br><br>

    <div class="container">
        <div id="Box">
            <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
            <div id="main">
            </div>
            <p style="text-align: center">{{ city_name }}未来14天天气,方向,风级</p>

            <div id="main2">
                <table class="table table-striped" style="width: 90%;text-align: center;margin: 0 auto;">
                    <tr>
                        <td>日期</td>
                        <td>天气</td>
                        <td>方向1</td>
                        <td>风向2</td>
                        <td>风级</td>
                    </tr>
                    {% for index in range(0, 14) %}
                        <tr>
                            <td>{{ time_14d[index] }}</td>
                            <td>{{ tianqi_14d[index] }}</td>
                            <td>{{ fangxiang1_14d[index] }}</td>
                            <td>{{ fengxiang2_14d[index] }}</td>
                            <td>{{ fengji_14d[index] }}</td>
                        </tr>
                    {% endfor %}
                </table>
            </div>
        </div>
    </div>

    <!-- 导入footer.html -->
    {% include 'footer.html' %}
</div>
<a href="#" class="scrollup"><i class="fa fa-angle-up active"></i></a>
<!-- javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->

<script type="application/javascript">
    // 基于准备好的dom,初始化echarts实例
    var myChart = echarts.init(document.getElementById('every_hour'));

    // 指定图表的配置项和数据
    // prettier-ignore
    let dataAxis = {{ time_1d }};
    // prettier-ignore
    let data = {{ temp_1d }};
    let yMax = 500;
    let dataShadow = [];
    for (let i = 0; i < data.length; i++) {
        dataShadow.push(yMax);
    }
    option = {
        title: {
            text: '{{ city_name }}每小时气温变化',
            left: '40%'  // 设置标题居中对齐
        },
        tooltip: {
            trigger: 'axis',
            axisPointer: {
                type: 'shadow'
            }
        },
        xAxis: {
            data: dataAxis,
            axisLabel: {
                inside: true,
                color: '#ff9818'
            },
            axisTick: {
                show: false
            },
            axisLine: {
                show: false
            },
            z: 10
        },
        yAxis: {
            axisLine: {
                show: false
            },
            axisTick: {
                show: false
            },
            axisLabel: {
                color: '#999'
            }
        },
        dataZoom: [
            {
                type: 'inside'
            }
        ],
        series: [
            {
                type: 'bar',
                showBackground: true,
                itemStyle: {
                    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                        {offset: 0, color: '#83bff6'},
                        {offset: 0.5, color: '#188df0'},
                        {offset: 1, color: '#188df0'}
                    ])
                },
                emphasis: {
                    itemStyle: {
                        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                            {offset: 0, color: '#2378f7'},
                            {offset: 0.7, color: '#2378f7'},
                            {offset: 1, color: '#83bff6'}
                        ])
                    }
                },
                data: data
            }
        ]
    };
    // Enable data zoom when user click bar.
    const zoomSize = 6;
    myChart.on('click', function (params) {
        console.log(dataAxis[Math.max(params.dataIndex - zoomSize / 2, 0)]);
        myChart.dispatchAction({
            type: 'dataZoom',
            startValue: dataAxis[Math.max(params.dataIndex - zoomSize / 2, 0)],
            endValue:
                dataAxis[Math.min(params.dataIndex + zoomSize / 2, data.length - 1)]
        });
    });

    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);


    // 基于准备好的dom,初始化echarts实例
    var myChart = echarts.init(document.getElementById('shidu_zhiliang'));

    // 指定图表的配置项和数据
    option = {
        title: {
            text: '{{ city_name }}每小时相对湿度,空气质量可视化分析',
            left: '10%' // 设置标题居中对齐
        },
        tooltip: {
            trigger: 'axis'
        },
        legend: {
            data: ['相对湿度', '空气质量']
        },
        grid: {
            left: '3%',
            right: '4%',
            bottom: '3%',
            containLabel: true
        },
        toolbox: {
            feature: {
                saveAsImage: {}
            }
        },
        xAxis: {
            type: 'category',
            boundaryGap: false,
            data: {{ time_1d }}
        },
        yAxis: {
            type: 'value'
        },
        series: [
            {
                name: '相对湿度',
                type: 'line',
                stack: 'Total',
                data: {{ shidu_1d }},
                label: {
                    position: 'right'  // 设置参数靠右摆放
                }
            },
            {
                name: '空气质量',
                type: 'line',
                stack: 'Total',
                data: {{ air_1d }},
                label: {
                    position: 'right'  // 设置参数靠右摆放
                }
            },
        ]
    };

    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);


    //未来一周气温变化图
    var myChart = echarts.init(document.getElementById('main'));
    // 指定图表的配置项和数据
    option = {
        title: {
            text: '{{ city_name }}未来14天气温变化图',
            left: '40%'  // 设置标题居中对齐
        },
        grid: {
            left: '5%',
            right: '9%'
        },
        tooltip: {
            trigger: 'axis'
        },
        legend: {
            x: 'right',
            y: 'top',
            padding: [35, 10, 5, 10],
        },
        toolbox: {
            show: true,
            feature: {
                dataZoom: {
                    yAxisIndex: 'none'
                },
                dataView: {readOnly: false},
                magicType: {type: ['line', 'bar']},
                restore: {},
                saveAsImage: {}
            }
        },
        xAxis: {
            type: 'category',
            boundaryGap: false,
            data: {{ time_14d }}
        },
        yAxis: {
            type: 'value',
            axisLabel: {
                formatter: '{value} °C'
            }
        },
        series: [
            {
                name: '最高温',
                type: 'line',
                data: {{ temp_max }},
                markPoint: {
                    data: [
                        {type: 'max', name: 'Max'},
                        {type: 'min', name: 'Min'}
                    ]
                },
                markLine: {
                    data: [{type: 'average', name: 'Avg'}]
                }
            },
            {
                name: '最低温',
                type: 'line',
                data: {{ temp_min }},
                markPoint: {
                    data: [{name: '周最低', value: -2, xAxis: 1, yAxis: -1.5}]
                },
                markLine: {
                    data: [
                        {type: 'average', name: 'Avg'},
                        [
                            {
                                symbol: 'none',
                                x: '90%',
                                yAxis: 'max'
                            },
                            {
                                symbol: 'circle',
                                label: {
                                    position: 'start',
                                    formatter: 'Max'
                                },
                                type: 'max',
                                name: '最高点'
                            }
                        ]
                    ]
                }
            }
        ]
    };
    // 使用刚指定的配置项和数据显示图表。
    myChart.setOption(option);
</script>

<script src="../static/js/jquery.js"></script>
<script src="../static/js/jquery.easing.1.3.js"></script>
<script src="../static/js/bootstrap.min.js"></script>
<script src="../static/js/jquery.fancybox.pack.js"></script>
<script src="../static/js/jquery.fancybox-media.js"></script>
<script src="../static/js/jquery.flexslider.js"></script>
<script src="../static/js/animate.js"></script>
<!-- Vendor Scripts -->
<script src="../static/js/modernizr.custom.js"></script>
<script src="../static/js/jquery.isotope.min.js"></script>
<script src="../static/js/jquery.magnific-popup.min.js"></script>
<script src="../static/js/animate.js"></script>
<script src="../static/js/custom.js"></script>
</body>
</html>

上一篇 下一篇