OceanSide On my own FEET
Fork me on GitHub

Python 作业5:数据可视化2

一、散点图

1、作业一

(1) 作业要求

使用IRIS数据集,在一个figure中绘制出下方的16个子图。 分别使用花瓣长度、花瓣宽度、花萼长度和花萼宽度这四种数据,两两组合,形成散点。


(2) 作业分析与代码实现

  1. 使用IRIS数据集,需要引用pandas库对数据集读入分析;同时注意观察图中16个子图的横纵坐标,使用正确的数据作为每个子图的横纵坐标轴刻度;数据集概述如下:
  1. 注意对类别去重,三种散点颜色分别为:绿:Iris-virginica;黄:Iris-versicolor;蓝:Iris-setosa;两两搭配可得横纵坐标轴分别为:['Sepal.length', 'Sepal.width', 'Petal.Length', 'Petal.Width']['Petal.Width', 'Petal.Length', 'Sepal.width', 'Sepal.length']

  2. 得到横纵坐标轴的列表,便可用两重for循环将其两两组合,通过列表元素得到数据集的对应数据(dataframe类型变量:iris存储);

  3. 使用subplot绘制子图,注意参数为(4, 4, n),n为子图编号,每轮循环进行自加;

  4. 对图添加轴标签和标题plt.titleplt.xlabel plt.ylabel

  5. 以上便可得到大致图像,如下:

  1. 可以看到子图标题和x轴标签重合的现象,同时还未绘制图例;并且y轴坐标跨度过于大,无法清晰显现散点的集群;
  2. 任务:子图间距、图例(要求中只有一个图例,在整个画布的左上方)、y轴坐标刻度间距:
# 1、设置子图之间距离:wspace为左右距离,hspace为上下间距
plt.subplots_adjust(left = 0.125, bottom = 0.1, right = 0.9, top = 0.9, wspace = 0.2, hspace = 0.8)
# 2、图例
if cnt == 1:
    """ 设置legend的位置,将其放在图外,并且只有第一幅子图时才绘制 """
    plt.legend(loc = 'upper left', bbox_to_anchor = (-0.75, 1.12), borderaxespad = 0.)
# 3、y轴坐标刻度
y_major_locator=MultipleLocator(1)
ax=plt.gca()
ax.yaxis.set_major_locator(y_major_locator)
  1. 综合上述思路,可编写代码如下:
"""数据可视化:散点图1"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.pyplot import MultipleLocator

fig = plt.figure(dpi=80)
# 读取数据
colors = ['b', 'y', 'g']            # 定义三种散点的颜色
iris = pd.read_csv('iris.csv')
species = iris.Species.unique()     # 对类别去重,三种类别

attributes1 = ['Sepal.length', 'Sepal.width', 'Petal.Length', 'Petal.Width']
attributes2 = ['Petal.Width', 'Petal.Length', 'Sepal.width', 'Sepal.length']
# 循环绘图,attributes中的搭配
cnt = 1
for i in range(len(attributes1)):
    for j in range(len(attributes2)):
        plt.subplot(4, 4, cnt)   # 设置子图16个,一行4列,画第cnt个
        for k in range(len(species)):
            plt.scatter(iris.loc[iris.Species == species[k], attributes2[j]],
                        iris.loc[iris.Species == species[k], attributes1[i]],
                        s = 15, c = colors[k], label = species[k])
        # 添加轴标签和标题
        plt.title(attributes1[i].split('.')[1] + ' vs ' + attributes2[j].split('.')[1])
        plt.xlabel(attributes2[j])
        plt.ylabel(attributes1[i])
        plt.grid(True, linestyle = '--', alpha = 0.8)   # 设置网格线
        # 设置坐标刻度
        y_major_locator=MultipleLocator(1)
        ax=plt.gca()
        ax.yaxis.set_major_locator(y_major_locator)
        if cnt == 1:
            """ 设置legend的位置,将其放在图外 """
            plt.legend(loc = 'upper left', bbox_to_anchor = (-0.75, 1.12), borderaxespad = 0.)  
        # 该子图绘图结束要绘制下一个子图
        cnt = cnt + 1

# 设置子图之间距离:wspace为左右距离,hspace为上下间距
plt.subplots_adjust(left = 0.125, bottom = 0.1, right = 0.9, top = 0.9, wspace = 0.2, hspace = 0.8)
 
plt.show()

(3) 效果演示

说明:遗憾的是,以我目前的水平没有办法指定子图长宽尺寸,所以子图都是长条状,y轴较短,美观上无法与示例图相比


二、饼图

2、作业二

(1) 作业要求

  1. 找一组自己感兴趣的真实数据,绘制出饼图。并看看数据的项数在什么范围比较合适在饼图中展示;
  2. 调整数据的顺序或角度,使得第一个扇区在12点方向开始;
  3. 调整字体的大小、标签的位置等参数。

(2) 作业分析与代码实现

  1. 我选择作业给定的中国大学数量csv文件:“中国大学数量.csv”中的2017年高考人数来绘制饼图;
  2. 观察csv文件的数据,可以看到2017年高考人数对应的索引是:“高考人数”,而2016年对应的是空索引(比较神奇);
  1. 要得到可用于计算的人数,要对提取的数据进行预处理(str方法);
  2. 由于要判断:数据的项数在什么范围比较合适在饼图中展示、调整字体的大小、标签的位置等参数,我的解决方法:打印未处理过数据的饼图和处理过数据的饼图进行对比、打印使用多种数据项数的子图饼图(从2->10)对比判断;
  3. 通过以上思路,编写代码如下:
"""数据可视化:饼图"""

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
from matplotlib import font_manager as fm
import copy


# 读取中国大学数量csv文件,用其中的2017年高考人数制作饼图
df = pd.read_csv('中国大学数量.csv', encoding = 'utf-8')
ls = df.高考人数.tolist()
ls.pop(0)
for i in range(len(ls)):
    """此时ls中的数据均以万为单位,所以要删除'万'字符"""
    ls[i] = float(ls[i].replace('万', ''))
total = 0
for emp in ls:
    """计算高考总人数"""
    total += emp


def setSize(ls, l):
    """计算各区间省份数"""
    upper = max(ls)
    step = (upper + 10) // l     # 设置划分区间步长
    dic = [i for i in range(l)]
    for emp in ls:
        section = int(emp // step)
        dic[section] = dic[section] + 1
    return dic


""" 打印最原始的饼图,与之后调整后的饼图对比 """
matplotlib.rcParams['font.sans-serif'] = ['SimHei']         #支持中文的细黑体
label = ["优惠模式", "普通模式", "困难模式", "噩梦模式", "地狱模式"]        # 设置标签
explode = [0, 0, 0, 0, 0.1]

size = setSize(ls, len(label))
plt.pie(size, explode = explode, labels = label, labeldistance = 1.1, autopct = "%1.1f%%", 
        shadow = True, startangle = 0, pctdistance = 0.6)


""" 显示多个子图,判断数据项数合适范围 """
label2 = ["困难模式", "噩梦模式", "地狱模式", '地狱模式1', '地狱模式2', '地狱模式3', '地狱模式4', '地狱模式5']  # 标签2
label3 = copy.deepcopy(label[0 : 2])
explode2 = [0, 0, 0.1, 0, 0, 0, 0, 0.1]
explode3 = copy.deepcopy(explode[0 : 2])
fig1 = plt.figure()      # 新的画布
for i in range(9):
    explode_list = copy.deepcopy(explode3)
    label_list = copy.deepcopy(label3)
    explode_list += explode2[0 : i]
    label_list += label2[0 : i]
    size = setSize(ls, len(label_list))
    plt.subplot(3, 3, i + 1)        # 设置九个子图
    print(label_list, explode_list)
    plt.pie(size, explode = explode_list, labels = label_list, labeldistance = 1.1, autopct = "%1.1f%%", 
            shadow = True, startangle = 0, pctdistance = 0.6)



""" 调整数据,使饼图从12点钟方向开始;并调整字体大小、标签位置;
    打印作为对比 """
fig2 = plt.figure()     # 新的画布,绘制调整后的饼图
size = setSize(ls, len(label))
size[0] -= 34 * 0.030   # 更改数据使饼图从12点钟方向开始
# labeldistance : label绘制位置,相对于半径的比例, 如<1则绘制在饼图内侧,默认值为1.1;改变该参数便可改变标签位置
patches, texts, autotexts = plt.pie(size, explode = explode, labels = label, labeldistance = 0.8, 
                                    autopct = "%1.1f%%", shadow = True, startangle = 0, pctdistance = 0.6)
# 调整字体大小
proptease = fm.FontProperties()
proptease.set_size('15')
# font size include: 'xx-small',x-small','small','medium','large','x-large','xx-large' or number, e.g. '12'
plt.setp(texts, fontproperties = proptease)
plt.setp(autotexts, fontproperties = proptease)


plt.show()

(3) 效果演示及结果分析

  1. 原始饼图:
  1. 调整数据和图上元素后的饼图,可以看到第一扇区是从12点钟开始的,我是调小了属于优惠模式的数据,使得其能呈现这一状态:
  1. 数据项数(2->10)子图对比:

  • 可以看到,对这个数据段来说:
    • 如果数据项数只有2、3项,则太不平衡,无法展示出数据的多样性和复杂性;
    • 数据项数在4->7项是比较合理的,既能展示出数据的细节、又不会太过臃肿和冗余;
    • 数据项数大于7之后就不适合了,因为饼图分得太多区块反而不利于数据分析,显得太过臃肿。

三、地图

3、 作业三

(1) 作业要求

在中国地图上展示每个省的高考人数或大学数量


(2) 作业分析与代码实现

  1. 同作业二,我选择各省的高考人数进行分析,文件:“中国大学数量.csv”;
  2. 在作业二中的打印已经让我对其中的数据有些印象,特别是2016年没有索引的数据,首先考虑如何获得2016年的数据,这里可以使用pandas函数iloc进行按列取数:
"""iloc:基于行索引和列索引(index,columns)都是从 0 开始"""
# iloc先行后列,中间用逗号(,)分割,例如取 a 和 A 对应的数据
frame.iloc[0,0]
# 取前两行对应数据
frame.iloc[0:2,:]
# 取前两列对应数据
frame.iloc[:,0:2]
  1. 同时注意,取出来的数据还是以“万”结尾的字符串,所以要对其进行预处理去除“万”同时转为float;
  2. 得到高考人数后,接下来就是比较简单的绘图了,从pyecharts引入options包和map包,用于绘制中国地图;
  3. 对着老师的代码照虎画猫(●ˇ∀ˇ●),贴一下核心代码:
def map_visualmap() -> map:
    global i
    c = (
        Map()
        .add("各省高考人数", [list(z) for z in zip(province, people[i])], "china")
        .set_global_opts(
            title_opts = opts.TitleOpts(title = "Map-VisualMap(连续型)"),
            visualmap_opts = opts.VisualMapOpts(min_ = min(people[i]) - 50000, max_ = max(people[i]) + 50000))
        .set_series_opts(label_opts = opts.LabelOpts(is_show = False))
    )
    return c
  1. 通过以上思路,可得最终代码如下:
""" 数据可视化:地图1"""

import pandas as pd
import numpy as np
from pyecharts import options as opts
from pyecharts.charts import Map
import random


# 读取中国大学数量csv文件,用其中的2017、2016年高考人数制作饼图
people = []
df = pd.read_csv('中国大学数量.csv', encoding = 'utf-8')
people.append(df.高考人数.tolist())
people[0].pop(0)            # 第一个元素是'2017年',删除
people.append(df.iloc[: , 2].tolist())
people[1].pop(0)            # 第一个元素是'2016年',删除
province = df.iloc[: , 0].tolist()
province.pop(0)             # 第一个元素是'省/市',删除
for j in range(2):
    """将读出数据转换为float"""
    for i in range(len(people[j])):
        """此时ls中的数据均以万为单位,所以要删除'万'字符"""
        people[j][i] = float(people[j][i].replace('万', ''))
        people[j][i] = people[j][i] * 10000

def map_visualmap() -> map:
    global i
    c = (
        Map()
        .add("各省高考人数", [list(z) for z in zip(province, people[i])], "china")
        .set_global_opts(
            title_opts = opts.TitleOpts(title = str(i + 2016) + "年全国高考人数分布情况"),
            visualmap_opts = opts.VisualMapOpts(min_ = min(people[i]) - 50000, max_ = max(people[i]) + 50000))
        .set_series_opts(label_opts = opts.LabelOpts(is_show = False))
    )
    return c

for i in range(2):
    map_visualmap().render(str(i + 2016) + "年全国高考人数" + ".html")

print('Done!')

(3) 效果演示

  1. 2016年:
  1. 2017年:

4、作业四

(1) 作业要求

展示自己家乡所在城市的温度变化热力图,要求至少有10天的数据。


(2) 作业分析及代码实现

  1. 所谓题目越短,难度越大。这题我觉得是7题中最难的题,包罗了爬虫、数据处理、数据可视化、地理历史等等知识点(诶好像混进去一个不对劲的东西);
  2. 这里先展示一下我要爬取的网站:http://www.tianqihoubao.com/lishi/ganzhou/month/202012.html:
  1. 查询过赣州市行政区划再开始动手(没错,我到现在才知道赣州市完整的行政区划),查看网页源代码:
  1. 了解到该网页把日期和气温都保存在<tr>下,这里直接通过接口爬取整个页面中的<tr>数据(也只有这一个表格),再从中挑选出我们需要的日期和气温,核心代码如下:
#数据提取
soup = BeautifulSoup(html, 'html.parser')
tr_list = soup.find_all('tr')

dates, temp = [], []
for data in tr_list[1:]:
    sub_data = data.text.split()
    dates.append(sub_data[0])
    temp.append(''.join(sub_data[3:6]))		# 气温被split分成三块,下标3:5
  1. 爬取赣州市17个区县从12月1日到12月10日的天气情况,分别储存在csv文件中,方便后续处理;
  2. 得到数据接着还要对其进行处理,因为气温不是我们要的格式,去除"℃"符号,得到当日最高温highs和最低温lows,取平均温度mid = (highs + lows) / 2作为绘图数据;
  3. 这里由于要陆续处理并绘制17个区县,所以定义了两个函数,简化代码方便运行:processing和geo_ganzhou;
  4. 生成png图片的代码和老师的大同小异,主要是使用到snapshot_phantomjs库里的snapshot函数,并不困难;麻烦的是配置环境,因为光是导入snapshot_phantomjs包还不够,得下载辅助运行的phantomjs.exe文件,该文件较大,并且还有可能出现不适配的情况(所幸我没遇到);下载完毕后将phantomjs.exe复制或剪切到存放python项目代码的目录下即可;
  5. 最后就是将生成的十张图片组合成gif了,要引入新的库:imageio,使用其中的imread和mimsave函数,可以很方便的绘制出gif图;
  6. 最终,综合上述,编写代码如下:

a、爬虫文件:homeWeather.py

"""爬虫:爬取天气数据"""

import requests
import pandas as pd
from bs4 import BeautifulSoup

def mySpider(position):
    #目标url
    url = 'http://www.tianqihoubao.com/lishi/{}/month/202012.html'.format(position)
    #获取网页源代码
    resp = requests.get(url)
    html = resp.content.decode('gbk')
    #数据提取
    soup = BeautifulSoup(html, 'html.parser')
    tr_list = soup.find_all('tr')

    dates, temp = [],[]
    for data in tr_list[1:]:
        sub_data = data.text.split()
        dates.append(sub_data[0])
        temp.append(''.join(sub_data[3:6]))		# 气温被split分成三块,下标3:5
    _data = pd.DataFrame()
    _data['日期'] = dates
    _data['气温'] = temp
    _data.to_csv('{}.csv'.format(position), index = False, encoding = 'gbk')   #去掉索引以及避免乱码

ganzhou = ['ganzhou', 'nankang', 'jxxinfeng', 'dayu', 'shangyou', 'chongyi', 
           'anyuan', 'jxlongnan', 'dingnan', 'quannan', 'ningdu', 'yudu', 'xingguo', 
           'huichang', 'xunwu', 'shicheng', 'ruijin']

for i in range(len(ganzhou)):
    mySpider(ganzhou[i])
    print('%s Compelte!' % ganzhou[i])

b、数据处理+数据可视化生成png文件:weatherMap.py

""" 数据可视化:地图2"""

from pyecharts import options as opts
from pyecharts.charts import Geo
from pyecharts.globals import ChartType
import random
from pyecharts.render import make_snapshot
from snapshot_phantomjs import snapshot
import csv
import pandas as pd
import numpy as np

Ganzhou = ["赣州市区", "南康区", "信丰县", "大余县", "上犹县", "崇义县", "安远县", 
           "龙南市", "定南县", "全南县", "宁都县", "于都县", "兴国县", "会昌县", "寻乌县", "石城县", "瑞金市"]
ganzhou = ['ganzhou', 'nankang', 'jxxinfeng', 'dayu', 'shangyou', 'chongyi', 
           'anyuan', 'jxlongnan', 'dingnan', 'quannan', 'ningdu', 'yudu', 'xingguo', 
           'huichang', 'xunwu', 'shicheng', 'ruijin']

# 创建字典对象存储天气
weather = {}
for i in range(len(ganzhou)):
    df = pd.read_csv('{}.csv'.format(ganzhou[i]), encoding = 'gbk')
    weather[ganzhou[i]] = df


def processing(data):
    """ 取出温度数据 """
    #数据处理
    data['最高气温'] = data['气温'].str.split('/',expand=True)[0]
    data['最低气温'] = data['气温'].str.split('/',expand=True)[1]
    data['最高气温'] = data['最高气温'].map(lambda x:int(x.replace('℃','')))
    data['最低气温'] = data['最低气温'].map(lambda x:int(x.replace('℃','')))

    dates = data['日期']
    highs = data['最高气温']
    lows = data['最低气温']
    print(dates)
    print(highs)
    print(lows)
    mid = (highs + lows) / 2          # 取平均气温
    print('%s temprature:' % (ganzhou[i]))
    print('平均气温\n', mid)
    return mid

temp = []
for i in range(len(ganzhou)):
    """ csv数据存储到temp列表中 """
    data = weather[ganzhou[i]]
    temp.append(processing(data).tolist())

dayTemp = []
for i in range(len(temp[0])):
    """ 将每天每个城市的气温放到一个列表 """
    everyTemp = []              # 第i天每个城市的温度
    for j in range(len(ganzhou)):
        everyTemp.append(temp[j][i])
    dayTemp.append(everyTemp)   # 爬取的天数里每个城市的温度

def geo_ganzhou(title) -> Geo:
    global i
    c = (
        Geo()
        .add_schema(maptype = "赣州")
        .add(
            title,
            [list(z) for z in zip(Ganzhou, dayTemp[i])],
            type_=ChartType.HEATMAP,
        )
        .set_global_opts(
            visualmap_opts = opts.VisualMapOpts(min_ = 0, max_ = max(temp[i]) + 5),
            title_opts = opts.TitleOpts(title = "江西省赣州市12月份各区县温度变化情况"), )
    )
    return c

for i in range(10):
    str_date="12月" + str(i + 1) + "日"
    print(str_date)
    make_snapshot(snapshot, geo_ganzhou(str_date).render(),
                  str(i + 1) + ".png", pixel_ratio = 1)

print('Done!')


c、生成gif图片文件:toGIF.py

"""生成gif"""

import imageio

outfilename = "ThermalChange.gif"   # 转化的GIF图片名称
filenames = []
for i in range(1, 11):
    """ 加入图片 """
    filename = '{}.png'.format(str(i))
    filenames.append(filename)


gif_images = []
for pic in filenames:
    gif_images.append(imageio.imread(pic))

imageio.mimsave("test.gif", gif_images, fps = 1)	# fps越小图片变换越慢

(3) 效果演示

注:由于12月1日到12月10日赣州地区气温变化并不大,所以gif图变化效果并不明显,得仔细看才能看到变动的地方。


四、3D绘图

5、作业五

(1) 作业要求

生成一个直方图,有25根直方柱。要求直方柱的最小值是1,最大值是25,要求沿着边缘,从外到内逐步增大


(2) 作业分析及代码实现

  1. 本题比较简单,算是熟练一下3D绘图工具吧,基本模板:
# meshgrid把X和Y变成平方长度,比如原来都是5,经过meshgrid和ravel之后,长度都变成了25,因为网格点是25个
xx, yy = np.meshgrid(X, Y)      # 网格化坐标
X, Y = xx.ravel(), yy.ravel()   # 矩阵扁平化
# 设置柱子Z属性
Z = Z.ravel()               # 矩阵扁平化,即将二维Z转化为一维
bottom = np.zeros_like(Z)   # 新建全0数组,shape和Z相同,即图中底部的位置
# width, depth, bottom
ax.bar3d(X, Y, bottom, width, depth, Z,  color = c, shade = True)     
  1. 这里有一点,刚开始我想直接导入mpl_toolkits包,但是提示没有合适的该包,百度了一下找到解决办法,即:
pip install --upgrade matplotlib
  1. 主要是实现要求:柱高要沿着边缘,从外到内逐步增大,Z坐标如图:
  1. 这里我没有想到简便的方法,所以直接按照坐标给Z赋值来实现效果了:
Z = np.zeros(shape = (5, 5))
Z[0] = [1, 2, 3, 4, 5]
Z[1] = [16, 17, 18, 19, 6]
Z[2] = [15, 24, 25, 20, 7]
Z[3] = [14, 23, 22, 21, 8]
Z[4] = [13, 12, 11, 10, 9]
  1. 综上所述,程序代码如下:
"""3D绘图:直方图"""

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
 
# 绘图设置
fig = plt.figure()
ax = fig.gca(projection = '3d')   # 三维坐标轴

"""数据设置"""
# X和Y的个数要相同
X = np.arange(0, 5, step = 1)     # X轴的坐标
Y = np.arange(0, 5, step = 1)     # Y轴的坐标
Z = np.zeros(shape = (5, 5))
Z[0] = [1, 2, 3, 4, 5]
Z[1] = [16, 17, 18, 19, 6]
Z[2] = [15, 24, 25, 20, 7]
Z[3] = [14, 23, 22, 21, 8]
Z[4] = [13, 12, 11, 10, 9]
# meshgrid把X和Y变成平方长度,比如原来都是5,经过meshgrid和ravel之后,长度都变成了25,因为网格点是25个
xx, yy = np.meshgrid(X, Y)      # 网格化坐标
X, Y = xx.ravel(), yy.ravel()   # 矩阵扁平化
# 设置柱子属性
Z = Z.ravel()               # 矩阵扁平化,即将二维Z转化为一维
bottom = np.zeros_like(Z)   # 新建全0数组,shape和Z相同,即图中底部的位置
width = depth = 0.8         # 柱子的长和宽

# 坐标轴设置
c = ['b'] * len(Z)            # 颜色数组,长度和Z一致
# 开始画图:本来的顺序是X, Y, Z, width, depth, bottom,但是那样会导致不能形成柱子,只有柱子顶端薄片,所以Z和bottom要互换
ax.bar3d(X, Y, bottom, width, depth, Z,  color = c, shade = True)     # width, depth, bottom
ax.set_xlabel('XLabel')
ax.set_ylabel('YLabel')
ax.set_zlabel('ZLabel')

plt.show()

(3) 效果演示

怎么说呢,感觉效果总比老师的差一点


6、作业六

(1) 作业要求

  1. 生成一个金字塔的线图
  2. 生成一上一下两个金字塔,叠放在一起

(2) 作业分析及代码实现

  1. 这题不难,只是有点繁琐,要对照每根线构造X、Y和Z的关系;譬如左边子图,共8条线段,每条线段的表达式都不一样,所以要分开画;
  2. 右边子图是左边子图叠放在左边子图的倒置图上,所以只要找到左边子图8条线段的表达式,右边子图的绘制也迎刃而解(改成负的就行了);
  3. 综上,实现代码如下:
"""3D绘图:线图"""

import numpy as np
import matplotlib.pyplot as plt
import math
from mpl_toolkits.mplot3d import Axes3D

# 1.生成fig对象和ax对象
fig = plt.figure()
ax1 = fig.add_subplot(121, projection = '3d')
ax2 = fig.add_subplot(122, projection = '3d')
ax1.set_xlabel('X Label')
ax1.set_ylabel('Y Label')
ax1.set_zlabel('Z Label')
ax2.set_xlabel('X Label')
ax2.set_ylabel('Y Label')
ax2.set_zlabel('Z Label')

# 2.生成数据
""" 子图1:金字塔的数据 """
x1 = np.arange(-1, 1.1, step = 0.25)      # 生成x轴的数据
y1 = np.arange(-1, 1.1, step = 0.25)      # 生成y轴的数据
z1 = 0
x2 = np.arange(-1, 0.1, step = 0.25)
z2 = x2 + 1
x3 = np.arange(-1, 0.1, step = 0.25)
z3 = x2 + 1
y4 = np.arange(-1, 0.1, step = 0.25)
z4 = y4 + 1
y5 = np.arange(0, 1.1, step = 0.25)
z5 = -y5 + 1


# 3.调用plot,画3D的线图
""" 子图1:金字塔 """
# 底
ax1.plot(np.array([-1 for x in range(9)]), y1, z1, "r")
ax1.plot(np.array([1 for x in range(9)]), y1, z1, "r")
ax1.plot(x1, np.array([-1 for x in range(9)]), z1, "r")
ax1.plot(x1, np.array([1 for x in range(9)]), z1, "r")
# 侧边
ax1.plot(x2, np.arange(-1, 0.1, step = 0.25), z2, "r")
ax1.plot(x3, np.arange(0, 1.1, step = 0.25)[::-1], z3, "r")
ax1.plot(np.arange(0, 1.1, step = 0.25)[::-1], y4, z4, "r")
ax1.plot(np.arange(0, 1.1, step = 0.25), y5, z5, "r")


""" 子图2:叠放金字塔 """
""" 上半部与子图1相同 """
# 底
ax2.plot(np.array([-1 for x in range(9)]), y1, z1, "r")
ax2.plot(np.array([1 for x in range(9)]), y1, z1, "r")
ax2.plot(x1, np.array([-1 for x in range(9)]), z1, "r")
ax2.plot(x1, np.array([1 for x in range(9)]), z1, "r")
# 侧边
ax2.plot(x2, np.arange(-1, 0.1, step = 0.25), z2, "r")
ax2.plot(x3, np.arange(0, 1.1, step = 0.25)[::-1], z3, "r")
ax2.plot(np.arange(0, 1.1, step = 0.25)[::-1], y4, z4, "r")
ax2.plot(np.arange(0, 1.1, step = 0.25), y5, z5, "r")

""" 下半部 """
x6 = np.arange(-1, 0.1, step = 0.25)
z6 = -x2 - 1
x7 = np.arange(-1, 0.1, step = 0.25)
z7 = -x2 - 1
y8 = np.arange(-1, 0.1, step = 0.25)
z8 = -y4 - 1
y9 = np.arange(0, 1.1, step = 0.25)
z9 = y5 - 1
# 侧边
ax2.plot(x6, np.arange(-1, 0.1, step = 0.25), z6, "b")
ax2.plot(x7, np.arange(0, 1.1, step = 0.25)[::-1], z7, "b")
ax2.plot(np.arange(0, 1.1, step = 0.25)[::-1], y8, z8, "b")
ax2.plot(np.arange(0, 1.1, step = 0.25), y9, z9, "b")


# 4.显示图形
plt.show()

(3) 效果演示


7、作业七

(1) 作业要求

生成一个散点图,如下图所示。z=x2+y2


(2) 作业分析及代码实现

  1. 图中上下两个形状都是由f(x, y) = z=x2+y2变化而来;

  2. 上面的:f1(x, y) = - f(x, y) + 20000;

  3. 下面的:f2(x, y) = f(x, y) - 20000;

  4. 注意散点的大小、形状和数量:上圆点,下三角点;我这里设置了点大小s = 10;共生成了2000个点(太多没有例图的效果,例图真的好看)

  5. 由上述,可编写代码如下:

""" 3D绘图:散点图 """

import numpy as np
import matplotlib.pyplot as plt
import math
from mpl_toolkits.mplot3d import Axes3D

# 1.生成fig对象和ax对象
fig = plt.figure()
ax = fig.add_subplot(projection = '3d')
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')


# 2.生成数据
# 3.调用scatter,画3D散点图

x1 = np.random.randint(-100, 100, 2000)    # x轴,生成2000个在-100到100之间的整数
y1 = np.random.randint(-100, 100, 2000)    # y轴,生成2000个在-100到100之间的整数
z1 = -x1 ** 2 - y1 ** 2 + 20000            # 生成z轴的数据
ax.scatter(x1, y1, z1, zdir = 'z', s = 10, c = 'b', marker = 'o',depthshade = True)


x2=np.random.randint(-100, 100, 2000)    # x轴,生成2000个在-100到100之间的整数
y2=np.random.randint(-100, 100, 2000)    # y轴,生成2000个在-100到100之间的整数
z2 = x2 ** 2 + y2 ** 2 - 20000          # 生成z轴的数据
ax.scatter(x2, y2, z2, zdir = 'z', s = 10, c = 'r', marker = '^',depthshade = True)

#4.显示图形
plt.show()

(3) 效果演示

posted @ 2020-12-11 19:47  EEthunder  阅读(915)  评论(0)    收藏  举报