大数据分析与可视化 之 实验11 Matplotlib绘制图表(一)

发布时间 2023-12-30 20:15:17作者: Ivan丶c

实验11 Matplotlib绘制图表(一)

实验学时:2学时
实验类型:验证
实验要求:必修

一、实验目的

  1. 掌握Matplotlib的框架及图形属性。
  2. 掌握Matplotlib绘制图形的步骤。
  3. 掌握Matplotlib绘制直线、曲线图、折线图。
  4. 掌握Matplotlib绘制柱形图、条形图、饼图。

二、实验要求

通过编程实现使用Matplotlib绘制直线、曲线图、折线图、柱形图、条形图并显示输出。

三、实验内容

任务1. 根据函数 ,绘制如下图所示图形。用Python编写程序实现。

任务2. 在任务1的基础上对图形进行美化,绘制如下图所示图形。用Python编写程序实现。

任务20. 在任务2的基础上,实现交互功能。参考代码如下:

任务3. 在实验9的任务2(如图)中结果数据绘制如下图形:
(1)根据每门课程的总分设计一个柱形图
(2)根据每门课程的平均分设计一个条形图
(3)根据每门课程的及格率和不及格率设计一个折线图。
用Python编写程序实现。

任务4. 编写一个程序,使用Matploglib分析学生考试成绩特征的分布与分散情况。
1.使用pandas库读取学生考试成绩数据
2.将学生考试总成绩分为4个区间,计算各区间下的学生人数,绘制学生考试总成绩分布饼图。
3.提取学生3项单科成绩的数据,绘制学生各项考试成绩分散情况箱线图。
分析学生考试总成绩的分布情况和3项单科成绩的分散情况。
参考代码:

test11.py

import numpy as np
import matplotlib.pyplot as plt
import os
import matplotlib as mpl
import pandas as pd
from matplotlib.font_manager import FontProperties
import matplotlib.animation as animation

import chapter09.test9

os.environ['MPL_SUPPRESS_MATLAB_ENGINE_WARNING'] = '1'
os.environ['MPLBACKEND'] = 'module://ipykernel.pylab.backend_inline'


# 定义函数
def Y1(x):
    return 2 * x + 1


def Y2(x):
    return -x ** 2 + 1


def task1():
    # 生成x值的范围
    x_values = np.linspace(-1, 1, 100)

    # 计算对应的y值
    y1_values = Y1(x_values)
    y2_values = Y2(x_values)

    font = FontProperties(fname=r'C:\Windows\Fonts\STSONG.TTF', size=12)
    # 绘制图形
    plt.plot(x_values, y2_values, label='曲线', color='blue', linestyle='-')
    plt.plot(x_values, y1_values, label='直线', color='red', linestyle='--')

    # 添加标签和标题
    plt.title('绘制直线和曲线', fontproperties=font)

    # 添加图例
    plt.legend(prop=font)

    # 显示图形
    plt.grid(True)
    plt.show()


def task2():
    # 生成x值的范围
    x_values = np.linspace(-1, 1, 100)

    # 计算对应的y值
    y1_values = Y1(x_values)
    y2_values = Y2(x_values)

    # 创建一个图形对象
    fig = plt.figure()

    # 设置整个图形的背景色为红色
    fig.set_facecolor('pink')

    font = FontProperties(fname=r'C:\Windows\Fonts\STSONG.TTF', size=12)
    # 绘制图形
    plt.plot(x_values, y2_values, label='曲线', color='blue', linestyle='-')
    plt.plot(x_values, y1_values, label='直线', color='red', linestyle='--')

    # 在线条上标出公式
    plt.text(0.5, 1.5, r'$Y1=2x+1$', fontsize=12, color='red')
    plt.text(-0.5, 1.2, r'$Y2=-x^2+1$', fontsize=12, color='blue')

    font2 = FontProperties(fname=r'C:\Windows\Fonts\STXINGKA.TTF', size=20)
    # 添加标签和标题
    plt.xlabel('x-变量', fontproperties=font, color='blue')
    plt.ylabel('y-函数的值', fontproperties=font, color='blue')
    plt.title('绘制直线和曲线', fontproperties=font2, color='red')

    # 添加图例
    legend = plt.legend(prop=font, loc='lower right', frameon=True, edgecolor='red')
    legend.get_frame().set_facecolor('gray')

    # 显示图形
    plt.grid(False)

    plt.show()


def draw_pic():
    x = np.linspace(-1, 1, 50)  # 从[-1,1]中等距取50个数作为x的取值
    y1 = 2 * x + 1
    plt.plot(x, y1, label='直线', color='red', linewidth=1.0, linestyle='--')  # 设置线条的样式
    y = -x ** 2 + 3
    plt.plot(x, y, label='曲线')  # lable表示图例标签

    plt.xlim((-1, 2))  # x参数范围,即x轴的取值范围
    plt.ylim((1, 3))  # y参数范围
    plt.xticks(np.linspace(-1, 2, 5))
    # 为点的位置设置对应文字,第一个参数是点的位置,第二个参数时点的文字提示
    plt.yticks([-2, -1.8, -1, 1.22, 3], [r'较差', r'差', r'一般', r'好', r'较好'])
    my_gca = plt.gca()  # 获取图形的axis轴
    # 将右边和上边的边框颜色去掉
    my_gca.spines['right'].set_color('none')
    my_gca.spines['top'].set_color('none')
    # 绑定x、y轴
    my_gca.xaxis.set_ticks_position('bottom')
    my_gca.yaxis.set_ticks_position('left')
    # 定义x、y轴位置
    my_gca.spines['bottom'].set_position(('data', 0))
    my_gca.spines['left'].set_position(('data', 0))
    plt.text(0.85, 2.6, r'状态曲线理想值', fontdict={'size': 16, 'color': 'g'})
    plt.legend(loc='lower right')


def dynamic_draw(fig, ax):
    x = 0.73
    y = 2 * x + 1
    global small_plot  # 声明小点为全局变量
    small_plot = ax.scatter(x, y, s=66, color='b')
    # 定义线的范围,x的范围是定值,y的范围是从y到0的位置,lw是linewidth,线宽
    line, = plt.plot([x, x], [y, 0], 'k-.', lw=2.5, color='red')  # 会返回两个参数 只取第一个
    # 设置关键位置的提示信息
    text = plt.annotate(r'$2x+1=%s$' % y, xy=(x, y), xycoords='data', xytext=(+30, -30), textcoords='offset points',
                        fontsize=16, arrowprops=dict(arrowstyle='->', connectionstyle='arc3,rad=.2'))

    def get_move(event):
        # 事先声明小点为全局变量 否则会被认为是局部变量报UnboundLocalErrol
        global small_plot
        # 打开交互模式面板
        plt.ion()
        try:
            if 1 > event.xdata > -1 and 3 > event.ydata > 0:
                x = event.xdata
                V = -x ** 2 + 3
                line.set_xdata([x, x])
                line.set_ydata([y, 0])
                small_plot.remove()  # 每次移动把原来的小点删了
                small_plot = ax.scatter(x, y, s=66, color='red')
                text.set_text(r'$2x+1=%s$' % y)
                text.xy = (x, y)
        except TypeError:
            pass

    # 绑定鼠标移动事件
    fig.canvas.mpl_connect('motion_notify_event', get_move)


def task2_2():
    # 解决中文乱码问题
    mpl.rcParams['font.sans-serif'] = ['SimHei']
    mpl.rcParams['axes.unicode_minus'] = False
    fig = plt.figure(facecolor='pink', edgecolor='green')
    ax = fig.add_subplot(1, 1, 1)

    draw_pic()
    dynamic_draw(fig, ax)
    plt.show()


def task3():
    # 解决中文乱码问题
    mpl.rcParams['font.sans-serif'] = ['SimHei']
    mpl.rcParams['axes.unicode_minus'] = False
    # 读取 Excel 文件
    df = pd.read_excel('mydata.xlsx', skiprows=3, skipfooter=2)
    # 为了方便演示,我仅选择部分列进行示例
    selected_columns = ['姓名', '性别', '高等数学', '大学英语', '操作系统', 'Python语言', '计算机组成原理']
    # 确保数据包含所需的列
    if set(selected_columns).issubset(df.columns):
        # (1) 根据每门课程的总分设计柱形图
        course_totals = df[selected_columns[2:]].sum()
        plt.figure(figsize=(10, 6))
        plt.bar(course_totals.index, course_totals.values, color='skyblue')
        plt.xlabel('课程')
        plt.ylabel('总分')
        plt.title('每门课程的总分柱形图')
        plt.show()
        # (2) 根据每门课程的平均分设计条形图
        course_means = df[selected_columns[2:]].mean()
        plt.figure(figsize=(10, 6))
        plt.barh(course_means.index, course_means.values, color='lightcoral')
        plt.xlabel('平均分')
        plt.ylabel('课程')
        plt.title('每门课程的平均分条形图')
        plt.show()
        # (3) 根据每门课程的及格率和不及格率设计折线图
        pass_rates = df[selected_columns[2:]].apply(lambda x: sum(x >= 60) / len(x))
        fail_rates = df[selected_columns[2:]].apply(lambda x: sum(x < 60) / len(x))
        plt.figure(figsize=(10, 6))
        plt.plot(pass_rates.index, pass_rates.values, label='及格率', marker='o', linestyle='-', color='green')
        plt.plot(fail_rates.index, fail_rates.values, label='不及格率', marker='o', linestyle='-', color='red')
        plt.xlabel('课程')
        plt.ylabel('比率')
        plt.title('每门课程的及格率和不及格率折线图')
        plt.legend()
        plt.show()
    else:
        print("数据缺少所需的列。请检查列名是否正确。")


def task4():
    student_grade = pd.read_excel('student_grade.xlsx')
    w = [0, 150, 200, 250, 300]
    grade_interval = pd.cut(student_grade.iloc[:, -1], w).value_counts()

    plt.rcParams['font.sans-serif'] = 'SimHei'  # 设置中文显示
    plt.rcParams['axes.unicode_minus'] = False
    # 绘制学生考试总成绩的总体分布情况饼图
    p = plt.figure(figsize=(12, 12))
    # 设置画布
    label = ["良好", "及格", "优秀", "不及格"]
    explode = [0.01, 0.01, 0.01, 0.01]  # 设定各项离心n个半径
    plt.pie(grade_interval, explode=explode, labels=label, autopct='%1.1f%%', textprops={"fontsize": 15})  # 绘制饼图
    plt.title('学生考试总成绩的总体分布情况饼图', fontsize=20)
    plt.savefig('学生考试总成绩的总体分布情况饼图.png')
    plt.show()

    # 绘制学生考试总成绩的总体分散情况箱线图
    math_grade = student_grade.iloc[:, -4]
    reading_grade = student_grade.iloc[:, -3]
    writing_grade = student_grade.iloc[:, -2]
    p = plt.figure(figsize=(16, 8))
    label = ['数学成绩', '阅读成绩', '写作成绩']
    gdp = (list(math_grade), list(reading_grade), list(writing_grade))
    plt.boxplot(gdp, notch=True, labels=label, meanline=True)  # 绘制箱线图
    plt.xlabel('学生考试科目')
    plt.ylabel('学生考试分数')
    plt.title('学生各项考试成绩的总体分散情况箱线图', fontsize=20)
    plt.savefig('学生各项考试成绩的总体分散情况箱线图.png')
    plt.show()


if __name__ == '__main__':
    task1()
    task2()
    task2_2()
    task3()
    task4()