Python 数据可视化与面向对象编程实战
1. Matplotlib 数据绘图
线图的一个重要用途是绘制函数的图形,即对于某个固定函数 f ,在一定范围的 x 值上绘制所有的点对 (x, f(x)) 。理论上,一个平滑、连续的图形由无限多个点组成。虽然我们无法使用无限个点,但使用的点越多,图形就越精确。以下是使用 1000 个点绘制 f(x) = sin(x) 从 x = 0 到 x = 10 的代码:
import numpy as np
import matplotlib.pyplot as plt
x_values = np.arange(0, 10, 0.01)
y_values = np.sin(x_values)
plt.plot(x_values, y_values)
2. Matplotlib 绘图定制
要了解更多关于 Matplotlib 绘图定制的信息,最好的方法是在需要实现特定功能时,在 matplotlib.org 上搜索文档。以下是一些控制 Matplotlib 绘图外观的重要方法:
- 设置绘图的比例和大小 :有时候绘图可能比例不协调,我们可以通过设置 x 和 y 轴的边界来解决。例如,将 x 和 y 轴的边界都设置为 0 到 5:
plt.ylim(0, 5)
plt.xlim(0, 5)
# 假设 plot_segment 是自定义的绘制线段的函数
plot_segment(point1, point2)
但这样可能仍然比例不准确,因为 x 轴和 y 轴上的一个单位长度可能视觉上不同。为了使它们在视觉上大小相同,我们可以将图形设置为正方形,使用 set_size_inches 方法:
plt.ylim(0, 5)
plt.xlim(0, 5)
plt.gcf().set_size_inches(5, 5)
# 假设 plot_segment 是自定义的绘制线段的函数
plot_segment(point1, point2)
- 设置坐标轴和图形的标签 :可以使用
plt.title函数为当前图形添加标题,使用plt.xlabel和plt.ylabel函数分别为x轴和y轴添加标签。例如,为正弦函数的图形添加标签:
x_values = np.arange(0, 10, 0.01)
y_values = np.sin(x_values)
plt.plot(x_values, y_values)
plt.title('Graph of sin(x) vs. x', fontsize=16)
plt.xlabel('this is the x value', fontsize=16)
plt.ylabel('the value of sin(x)', fontsize=16)
3. Python 面向对象编程
面向对象编程(OOP)是一种强调使用类来组织程序数据的编程范式。类可以存储称为属性的值以及称为方法的函数,这些方法将程序中的数据和功能联系起来。下面我们通过一个具体的例子来介绍 Python 中的类和 OOP。
3.1 定义类
假设我们正在编写一个处理几何形状的 Python 程序,例如一个绘图应用程序。我们可以定义一个 Rectangle 类来描述矩形的属性,并创建该类的实例来表示特定的矩形。
class Rectangle():
def __init__(self, w, h):
self.width = w
self.height = h
创建了构造函数后,我们可以像使用函数一样使用类名,传入两个数字并返回一个 Rectangle 对象。例如:
r = Rectangle(3, 4)
print(type(r)) # 输出: __main__.Rectangle
print(r.width) # 输出: 3
print(r.height) # 输出: 4
3.2 定义方法
方法是与类相关联的函数,用于计算实例的某些属性或为实例提供某种功能。对于矩形,我们可以定义一个 area() 方法来计算其面积:
class Rectangle():
def __init__(self, w, h):
self.width = w
self.height = h
def area(self):
return self.width * self.height
调用 area 方法计算矩形的面积:
print(Rectangle(3, 4).area()) # 输出: 12
我们还可以定义一个 scale 方法,该方法接受一个数字并返回一个新的 Rectangle 对象,其高度和宽度按该因子缩放:
class Rectangle():
def __init__(self, w, h):
self.width = w
self.height = h
def area(self):
return self.width * self.height
def scale(self, factor):
return Rectangle(factor * self.width, factor * self.height)
使用 scale 方法:
r = Rectangle(2, 1)
s = r.scale(3)
print(s.width) # 输出: 6
print(s.height) # 输出: 3
3.3 特殊方法
有些方法要么是自动可用的,要么在实现后具有特殊效果。例如, __dict__ 方法默认在每个新类的实例上可用,它返回实例所有属性的字典:
print(Rectangle(2, 1).__dict__) # 输出: {'width': 2, 'height': 1}
__eq__ 方法用于描述类实例上 == 运算符的行为,决定两个实例何时相等。默认情况下,不同的实例即使包含相同的数据也不相等,我们可以自定义 __eq__ 方法:
class Rectangle():
def __init__(self, w, h):
self.width = w
self.height = h
def area(self):
return self.width * self.height
def scale(self, factor):
return Rectangle(factor * self.width, factor * self.height)
def __eq__(self, other):
return self.width == other.width and self.height == other.height
使用自定义的 __eq__ 方法:
print(Rectangle(3, 4) == Rectangle(3, 4)) # 输出: True
__repr__ 方法用于生成对象的默认字符串表示:
class Rectangle():
def __init__(self, w, h):
self.width = w
self.height = h
def area(self):
return self.width * self.height
def scale(self, factor):
return Rectangle(factor * self.width, factor * self.height)
def __eq__(self, other):
return self.width == other.width and self.height == other.height
def __repr__(self):
return 'Rectangle (%r by %r)' % (self.width, self.height)
使用 __repr__ 方法:
print(Rectangle(3, 4)) # 输出: Rectangle (3 by 4)
3.4 运算符重载
我们可以实现更多的特殊方法来描述 Python 运算符在类实例上的行为,这种将已有含义的运算符重新用于新类的对象的做法称为运算符重载。例如,实现 __mul__ 和 __rmul__ 方法来处理乘法运算符:
class Rectangle():
def __init__(self, w, h):
self.width = w
self.height = h
def area(self):
return self.width * self.height
def scale(self, factor):
return Rectangle(factor * self.width, factor * self.height)
def __eq__(self, other):
return self.width == other.width and self.height == other.height
def __repr__(self):
return 'Rectangle (%r by %r)' % (self.width, self.height)
def __mul__(self, factor):
return self.scale(factor)
def __rmul__(self, factor):
return self.scale(factor)
使用运算符重载:
print(10 * Rectangle(1, 2)) # 输出: Rectangle (10 by 20)
print(Rectangle(1, 2) * 10) # 输出: Rectangle (10 by 20)
3.5 类方法
类方法是与类本身相关联的函数,而不是与单个实例相关联。对于 Rectangle 类,我们可以创建一个类方法作为替代构造函数,例如创建一个正方形:
class Rectangle():
def __init__(self, w, h):
self.width = w
self.height = h
def area(self):
return self.width * self.height
def scale(self, factor):
return Rectangle(factor * self.width, factor * self.height)
def __eq__(self, other):
return self.width == other.width and self.height == other.height
def __repr__(self):
return 'Rectangle (%r by %r)' % (self.width, self.height)
def __mul__(self, factor):
return self.scale(factor)
def __rmul__(self, factor):
return self.scale(factor)
@classmethod
def square(cls, side):
return Rectangle(side, side)
使用类方法:
print(Rectangle.square(5)) # 输出: Rectangle (5 by 5)
3.6 继承和抽象类
继承是 OOP 中的一个重要概念。如果说类 A 继承自类 B ,意味着类 A 的实例是类 B 的特殊情况,它们的行为类似于类 B 的实例,但具有一些额外或修改的功能。例如,我们可以创建一个 Square 类,它继承自 Rectangle 类:
class Square(Rectangle):
def __init__(self, s):
return super().__init__(s, s)
def __repr__(self):
return "Square (%r)" % self.width
使用 Square 类:
print(Square(5).area()) # 输出: 25
在 OOP 中,常见的模式是让两个类继承自同一个抽象基类。抽象基类定义了一些通用的方法或代码,但不能创建其实例。例如,我们可以创建一个 Shape 抽象基类,让 Rectangle 和 Circle 类继承自它:
from abc import ABC, abstractmethod
from math import pi
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def scale(self, factor):
pass
def __eq__(self, other):
return self.__dict__ == other.__dict__
def __mul__(self, factor):
return self.scale(factor)
def __rmul__(self, factor):
return self.scale(factor)
class Rectangle(Shape):
def __init__(self, w, h):
self.width = w
self.height = h
def area(self):
return self.width * self.height
def scale(self, factor):
return Rectangle(factor * self.width, factor * self.height)
class Circle(Shape):
def __init__(self, r):
self.radius = r
def area(self):
return pi * self.radius * self.radius
def scale(self, factor):
return Circle(factor * self.radius)
def __eq__(self, other):
return self.radius == other.radius
def __repr__(self):
return 'Circle (radius %r)' % self.radius
def __mul__(self, factor):
return self.scale(factor)
def __rmul__(self, factor):
return self.scale(factor)
使用继承和抽象类:
print(3 * Rectangle(1, 2) == Rectangle(3, 6)) # 输出: True
4. 使用 OpenGL 和 PyGame 加载和渲染 3D 模型
在编写图形变换和动画程序时,我们可以使用 OpenGL 和 PyGame 来替代 Matplotlib。下面我们将使用 PyOpenGL 和 PyGame 重新创建第 3 章中的八面体。
4.1 安装库
首先,我们需要安装 PyGame 和 PyOpenGL 库:
pip install PyGame
pip install PyOpenGL
4.2 重新创建八面体
在一个名为 octahedron.py 的新 Python 文件中,我们需要导入一些必要的库:
import pygame
from pygame.locals import *
from OpenGL.GL import *
from OpenGL.GLU import *
import matplotlib.cm
from vectors import *
from math import *
定义计算法线和阴影的函数:
def normal(face):
return (cross(subtract(face[1], face[0]), subtract(face[2], face[0])))
blues = matplotlib.cm.get_cmap('Blues')
def shade(face, color_map=blues, light=(1, 2, 3)):
return color_map(1 - dot(unit(normal(face)), unit(light)))
指定八面体的几何形状和光源:
light = (1, 2, 3)
faces = [
[(1, 0, 0), (0, 1, 0), (0, 0, 1)],
[(1, 0, 0), (0, 0, -1), (0, 1, 0)],
[(1, 0, 0), (0, 0, 1), (0, -1, 0)],
[(1, 0, 0), (0, -1, 0), (0, 0, -1)],
[(-1, 0, 0), (0, 0, 1), (0, 1, 0)],
[(-1, 0, 0), (0, 1, 0), (0, 0, -1)],
[(-1, 0, 0), (0, -1, 0), (0, 0, 1)],
[(-1, 0, 0), (0, 0, -1), (0, -1, 0)],
]
初始化 PyGame 并设置窗口:
pygame.init()
display = (400, 400)
window = pygame.display.set_mode(display, DOUBLEBUF | OPENGL)
配置 OpenGL 的视角:
gluPerspective(45, 1, 0.1, 50.0)
glTranslatef(0.0, 0.0, -5)
glEnable(GL_CULL_FACE)
glEnable(GL_DEPTH_TEST)
glCullFace(GL_BACK)
绘制八面体的主循环:
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
clock.tick()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glBegin(GL_TRIANGLES)
for face in faces:
color = shade(face, blues, light)
for vertex in face:
glColor3fv((color[0], color[1], color[2]))
glVertex3fv(vertex)
glEnd()
pygame.display.flip()
如果想查看帧率,可以在 while True 循环的末尾添加以下代码:
print(clock.get_fps())
总结
本文介绍了 Matplotlib 数据绘图和定制、Python 面向对象编程以及使用 OpenGL 和 PyGame 加载和渲染 3D 模型的相关知识。通过这些内容,我们可以更好地进行数据可视化和图形编程。
流程图
graph TD;
A[开始] --> B[Matplotlib 绘图]
B --> C[定制绘图]
C --> D[面向对象编程]
D --> E[定义类]
E --> F[定义方法]
F --> G[特殊方法]
G --> H[运算符重载]
H --> I[类方法]
I --> J[继承和抽象类]
J --> K[OpenGL 和 PyGame 渲染 3D 模型]
K --> L[安装库]
L --> M[重新创建八面体]
M --> N[结束]
表格
| 主题 | 描述 |
|---|---|
| Matplotlib 绘图 | 绘制函数图形,使用更多点使图形更精确 |
| Matplotlib 定制 | 设置绘图比例、大小和标签 |
| 面向对象编程 | 使用类组织程序数据,包括定义类、方法、特殊方法、运算符重载、类方法、继承和抽象类 |
| OpenGL 和 PyGame | 加载和渲染 3D 模型,如重新创建八面体 |
Python 数据可视化与面向对象编程实战
5. 深入理解代码流程与逻辑
为了更好地理解上述代码的执行过程,我们可以通过详细的流程图和表格来梳理。
5.1 Matplotlib 绘图流程
graph TD;
A[定义 x 范围] --> B[计算 y 值]
B --> C[绘制图形]
C --> D[定制图形外观]
D --> E[显示图形]
| 步骤 | 代码示例 | 说明 |
|---|---|---|
| 定义 x 范围 | x_values = np.arange(0, 10, 0.01) | 使用 np.arange 函数生成从 0 到 10,步长为 0.01 的 x 值数组 |
| 计算 y 值 | y_values = np.sin(x_values) | 对每个 x 值计算对应的 sin(x) 值 |
| 绘制图形 | plt.plot(x_values, y_values) | 使用 plt.plot 函数绘制图形 |
| 定制图形外观 | plt.title('Graph of sin(x) vs. x', fontsize=16) 等 | 设置标题、坐标轴标签等 |
| 显示图形 | (未明确写出,通常使用 plt.show() ) | 显示绘制好的图形 |
5.2 面向对象编程流程
graph TD;
A[定义类] --> B[定义构造函数]
B --> C[定义方法]
C --> D[定义特殊方法]
D --> E[运算符重载]
E --> F[定义类方法]
F --> G[继承和抽象类]
| 步骤 | 代码示例 | 说明 |
|---|---|---|
| 定义类 | class Rectangle(): | 使用 class 关键字定义类 |
| 定义构造函数 | def __init__(self, w, h): | 初始化类的属性 |
| 定义方法 | def area(self): | 为类添加功能 |
| 定义特殊方法 | def __eq__(self, other): | 自定义类的行为 |
| 运算符重载 | def __mul__(self, factor): | 重新定义运算符的行为 |
| 定义类方法 | @classmethod def square(cls, side): | 与类本身相关的函数 |
| 继承和抽象类 | class Square(Rectangle): 等 | 实现类的继承和抽象基类 |
5.3 OpenGL 和 PyGame 渲染 3D 模型流程
graph TD;
A[安装库] --> B[导入库]
B --> C[定义几何形状和光源]
C --> D[初始化 PyGame 和窗口]
D --> E[配置 OpenGL 视角]
E --> F[绘制主循环]
F --> G[结束程序]
| 步骤 | 代码示例 | 说明 |
|---|---|---|
| 安装库 | pip install PyGame 等 | 使用 pip 安装所需库 |
| 导入库 | import pygame 等 | 导入所需的 Python 库 |
| 定义几何形状和光源 | light = (1, 2, 3) 等 | 指定 3D 模型的几何形状和光源 |
| 初始化 PyGame 和窗口 | pygame.init() 等 | 初始化 PyGame 并设置窗口 |
| 配置 OpenGL 视角 | gluPerspective(45, 1, 0.1, 50.0) 等 | 配置 OpenGL 的视角和渲染选项 |
| 绘制主循环 | while True: 等 | 不断绘制和更新 3D 模型 |
| 结束程序 | pygame.quit() 等 | 退出 PyGame 程序 |
6. 实际应用场景
这些技术在实际应用中有广泛的用途,以下是一些常见的场景:
6.1 数据可视化
使用 Matplotlib 可以将各种数据以直观的图形展示出来,帮助我们更好地理解数据。例如,在数据分析中,我们可以绘制折线图、柱状图、散点图等,展示数据的趋势、分布等特征。
import numpy as np
import matplotlib.pyplot as plt
# 生成示例数据
x = np.linspace(0, 10, 100)
y = np.sin(x)
# 绘制折线图
plt.plot(x, y)
plt.title('Sine Wave')
plt.xlabel('X')
plt.ylabel('Y')
plt.show()
6.2 游戏开发
OpenGL 和 PyGame 可以用于开发 2D 和 3D 游戏。通过创建各种几何形状和动画效果,我们可以实现简单的游戏,如平台游戏、射击游戏等。例如,上述的八面体渲染可以作为游戏中的一个元素,通过不断变换其位置、大小和颜色,实现动画效果。
6.3 图形设计
面向对象编程的思想可以帮助我们更好地组织和管理图形元素。例如,在一个绘图应用程序中,我们可以定义不同的图形类(如矩形、圆形、三角形等),并为它们添加各种属性和方法,如移动、旋转、缩放等。
class Shape:
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, dx, dy):
self.x += dx
self.y += dy
class Rectangle(Shape):
def __init__(self, x, y, width, height):
super().__init__(x, y)
self.width = width
self.height = height
def draw(self):
print(f"Drawing rectangle at ({self.x}, {self.y}) with width {self.width} and height {self.height}")
# 创建矩形对象
rect = Rectangle(10, 20, 50, 30)
rect.draw()
rect.move(5, 10)
rect.draw()
7. 总结与展望
通过本文的介绍,我们学习了 Matplotlib 绘图、面向对象编程以及 OpenGL 和 PyGame 渲染 3D 模型的相关知识。这些技术为我们提供了强大的工具,用于数据可视化和图形编程。
在未来,我们可以进一步探索这些技术的应用,例如:
- 结合机器学习算法,实现更复杂的数据可视化,如绘制决策边界、聚类结果等。
- 开发更复杂的游戏,添加更多的游戏元素和关卡。
- 设计更高级的图形应用程序,支持更多的图形操作和特效。
希望本文能为你在数据可视化和图形编程方面提供一些帮助,激发你进一步探索的兴趣。
流程图
graph TD;
A[开始应用] --> B[选择应用场景]
B --> C{数据可视化}
B --> D{游戏开发}
B --> E{图形设计}
C --> F[使用 Matplotlib 绘图]
D --> G[使用 OpenGL 和 PyGame 渲染]
E --> H[使用面向对象编程设计图形类]
F --> I[分析数据]
G --> J[开发游戏元素]
H --> K[设计图形操作]
I --> L[结束应用]
J --> L
K --> L
表格
| 应用场景 | 技术工具 | 实现步骤 |
|---|---|---|
| 数据可视化 | Matplotlib | 定义数据、选择图形类型、绘制图形、定制外观、显示图形 |
| 游戏开发 | OpenGL 和 PyGame | 安装库、导入库、定义几何形状和光源、初始化窗口、配置视角、绘制主循环 |
| 图形设计 | 面向对象编程 | 定义图形类、实现构造函数、添加属性和方法、实现继承和多态 |
超级会员免费看


被折叠的 条评论
为什么被折叠?



