第二阶段_技术栈过渡-Day 3: 数据可视化(Matplotlib和Seaborn)

30 阅读17分钟

Day 3: 数据可视化(Matplotlib和Seaborn)

学习目标

  • 理解数据可视化的重要性和基本原则
  • 掌握Matplotlib的基本绘图功能和自定义选项
  • 学习Seaborn库创建统计图表的方法
  • 了解不同类型图表的适用场景
  • 掌握图表美化和定制技巧

1. 数据可视化简介

1.1 什么是数据可视化

数据可视化是将数据转换为图形表示的过程,目的是通过视觉元素(如图表、图形和地图)来传达数据中的关系和模式。

定义:数据可视化是利用计算机图形学和图像处理技术,将数据转换为图形或图像形式展示,并进行交互的理论、方法和技术。

核心目标

  • 清晰有效地传达信息
  • 揭示数据中的模式、趋势和异常
  • 支持决策和分析过程
  • 讲述数据背后的故事

1.2 数据可视化的重要性

在数据分析中的作用

  • 快速理解大量数据
  • 发现隐藏的模式和关系
  • 识别异常值和趋势
  • 有效沟通分析结果
  • 支持假设验证和决策制定

在机器学习中的应用

  • 数据探索和理解
  • 特征工程和选择
  • 模型性能评估
  • 结果解释和展示
  • 模型行为可视化

1.3 Python可视化生态系统

graph TD
    A[Python可视化生态] --> B[基础绘图库]
    A --> C[统计绘图库]
    A --> D[交互式可视化]
    A --> E[地理空间可视化]
    A --> F[专业领域可视化]
    
    B --> B1[Matplotlib]
    B --> B2[Plotly]
    
    C --> C1[Seaborn]
    C --> C2[ggplot]
    
    D --> D1[Bokeh]
    D --> D2[Plotly Express]
    D --> D3[Altair]
    
    E --> E1[Folium]
    E --> E2[GeoPandas]
    
    F --> F1[NetworkX]
    F --> F2[PyVista]
    
    style A fill:#f9f,stroke:#333,stroke-width:2px
    style B fill:#bbf,stroke:#333,stroke-width:2px
    style C fill:#bbf,stroke:#333,stroke-width:2px
    style D fill:#bbf,stroke:#333,stroke-width:2px
    style E fill:#bbf,stroke:#333,stroke-width:2px
    style F fill:#bbf,stroke:#333,stroke-width:2px

主要可视化库

  • Matplotlib:Python最流行的绘图库,提供了创建静态、动画和交互式可视化的完整平台
  • Seaborn:基于Matplotlib的统计数据可视化库,提供了更高级的接口和美观的默认样式
  • Plotly:创建交互式图表的库,支持网页展示和仪表板
  • Bokeh:针对Web浏览器的交互式可视化库
  • Altair:声明式统计可视化库,基于Vega和Vega-Lite
  • Folium:地理空间数据可视化库,基于Leaflet.js

1.4 可视化与JAVA对比

特性JAVAPython
可视化库JFreeChart, JavaFXMatplotlib, Seaborn, Plotly
集成度需要额外配置与数据处理库无缝集成
易用性代码冗长简洁直观
定制性高但复杂高且相对简单
交互性有限(主要通过JavaFX)丰富(多种交互式库)
输出格式有限多样(PNG, PDF, SVG, HTML等)

JAVA示例

// JAVA使用JFreeChart创建折线图
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.data.category.DefaultCategoryDataset;

import java.io.File;
import java.io.IOException;

public class LineChartExample {
    public static void main(String[] args) {
        // 创建数据集
        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        dataset.addValue(1.0, "Series1", "Type1");
        dataset.addValue(4.0, "Series1", "Type2");
        dataset.addValue(3.0, "Series1", "Type3");
        dataset.addValue(5.0, "Series1", "Type4");
        
        // 创建图表
        JFreeChart chart = ChartFactory.createLineChart(
            "Line Chart Example",  // 标题
            "Category",            // x轴标签
            "Value",               // y轴标签
            dataset                // 数据集
        );
        
        // 保存图表
        try {
            ChartUtils.saveChartAsPNG(new File("line_chart.png"), chart, 500, 300);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Python示例

# Python使用Matplotlib创建折线图
import matplotlib.pyplot as plt

# 数据
categories = ['Type1', 'Type2', 'Type3', 'Type4']
values = [1.0, 4.0, 3.0, 5.0]

# 创建图表
plt.figure(figsize=(5, 3))
plt.plot(categories, values, marker='o')
plt.title('Line Chart Example')
plt.xlabel('Category')
plt.ylabel('Value')
plt.grid(True)

# 保存图表
plt.savefig('line_chart.png')
plt.show()

2. Matplotlib基础

2.1 Matplotlib架构

Matplotlib是一个多层次的库,提供了不同级别的接口来满足不同的需求。

graph TD
    A[Matplotlib架构] --> B[后端层]
    A --> C[艺术家层]
    A --> D[脚本层]
    
    B --> B1[渲染引擎]
    B --> B2[输出格式]
    
    C --> C1[Figure]
    C --> C2[Axes]
    C --> C3[Axis]
    C --> C4[Artist对象]
    
    D --> D1[pyplot模块]
    D --> D2[面向对象接口]
    
    style A fill:#f9f,stroke:#333,stroke-width:2px
    style B fill:#bbf,stroke:#333,stroke-width:2px
    style C fill:#bbf,stroke:#333,stroke-width:2px
    style D fill:#bbf,stroke:#333,stroke-width:2px

主要组件

  • Figure:整个图表对象,可以包含多个Axes
  • Axes:图表区域,包含数据可视化
  • Axis:坐标轴对象
  • Artist:图表中的各种元素(线条、文本、标记等)

两种接口

  • pyplot接口:状态机风格,简单易用
  • 面向对象接口:更灵活,适合复杂图表

2.2 基本绘图

import matplotlib.pyplot as plt
import numpy as np

# 创建数据
x = np.linspace(0, 10, 100)
y = np.sin(x)

# 使用pyplot接口
plt.figure(figsize=(8, 4))  # 设置图表大小
plt.plot(x, y, 'b-', label='sin(x)')  # 绘制线条
plt.title('Sine Wave')  # 设置标题
plt.xlabel('x')  # 设置x轴标签
plt.ylabel('sin(x)')  # 设置y轴标签
plt.grid(True)  # 显示网格
plt.legend()  # 显示图例
plt.savefig('sine_wave.png')  # 保存图表
plt.show()  # 显示图表

# 使用面向对象接口
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(x, y, 'b-', label='sin(x)')
ax.set_title('Sine Wave')
ax.set_xlabel('x')
ax.set_ylabel('sin(x)')
ax.grid(True)
ax.legend()
fig.savefig('sine_wave_oo.png')
plt.show()

2.3 常见图表类型

2.3.1 线图(Line Plot)

线图用于显示连续数据的趋势,特别适合时间序列数据。

# 线图示例
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)

plt.figure(figsize=(10, 6))
plt.plot(x, y1, 'b-', label='sin(x)')
plt.plot(x, y2, 'r--', label='cos(x)')
plt.title('Sine and Cosine Waves')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.grid(True)
plt.show()
2.3.2 散点图(Scatter Plot)

散点图用于显示两个变量之间的关系,每个点代表一个观测值。

# 散点图示例
np.random.seed(42)
x = np.random.rand(50)
y = x + np.random.normal(0, 0.2, 50)

plt.figure(figsize=(8, 6))
plt.scatter(x, y, c='blue', alpha=0.6, s=100)  # s控制点大小
plt.title('Scatter Plot Example')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)
plt.show()
2.3.3 柱状图(Bar Plot)

柱状图用于比较不同类别的数量或大小。

# 柱状图示例
categories = ['A', 'B', 'C', 'D', 'E']
values = [25, 40, 30, 55, 15]

plt.figure(figsize=(8, 6))
plt.bar(categories, values, color='skyblue', edgecolor='black')
plt.title('Bar Plot Example')
plt.xlabel('Category')
plt.ylabel('Value')
plt.grid(True, axis='y')
plt.show()
2.3.4 直方图(Histogram)

直方图用于显示数值数据的分布情况。

# 直方图示例
np.random.seed(42)
data = np.random.normal(0, 1, 1000)  # 生成正态分布数据

plt.figure(figsize=(8, 6))
plt.hist(data, bins=30, color='skyblue', edgecolor='black', alpha=0.7)
plt.title('Histogram Example')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.grid(True)
plt.show()
2.3.5 饼图(Pie Chart)

饼图用于显示部分与整体的关系。

# 饼图示例
labels = ['A', 'B', 'C', 'D', 'E']
sizes = [15, 30, 25, 10, 20]
explode = (0, 0.1, 0, 0, 0)  # 突出第二个扇区

plt.figure(figsize=(8, 8))
plt.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%',
        shadow=True, startangle=90)
plt.axis('equal')  # 保证饼图是圆的
plt.title('Pie Chart Example')
plt.show()
2.3.6 箱线图(Box Plot)

箱线图用于显示数据的分布情况,包括中位数、四分位数和异常值。

# 箱线图示例
np.random.seed(42)
data = [np.random.normal(0, std, 100) for std in range(1, 6)]

plt.figure(figsize=(10, 6))
plt.boxplot(data, labels=['1', '2', '3', '4', '5'])
plt.title('Box Plot Example')
plt.xlabel('Group')
plt.ylabel('Value')
plt.grid(True)
plt.show()
2.3.7 热图(Heatmap)

热图用于显示矩阵数据,颜色表示数值大小。

# 热图示例
import numpy as np

# 创建相关矩阵
np.random.seed(42)
data = np.random.rand(10, 10)
corr = np.corrcoef(data)

plt.figure(figsize=(8, 6))
plt.imshow(corr, cmap='coolwarm')
plt.colorbar()
plt.title('Heatmap Example')
plt.xticks(range(10))
plt.yticks(range(10))
plt.show()

2.4 子图和布局

Matplotlib提供了多种创建子图和控制布局的方法。

# 创建子图
plt.figure(figsize=(12, 8))

# 2x2网格,第1个位置
plt.subplot(2, 2, 1)
plt.plot(np.random.rand(10))
plt.title('Subplot 1')

# 2x2网格,第2个位置
plt.subplot(2, 2, 2)
plt.scatter(np.random.rand(10), np.random.rand(10))
plt.title('Subplot 2')

# 2x2网格,第3个位置
plt.subplot(2, 2, 3)
plt.bar(range(5), np.random.rand(5))
plt.title('Subplot 3')

# 2x2网格,第4个位置
plt.subplot(2, 2, 4)
plt.hist(np.random.randn(1000))
plt.title('Subplot 4')

plt.tight_layout()  # 自动调整子图参数
plt.show()

# 使用GridSpec创建不规则布局
import matplotlib.gridspec as gridspec

fig = plt.figure(figsize=(12, 8))
gs = gridspec.GridSpec(2, 3)

ax1 = fig.add_subplot(gs[0, :2])  # 第一行,前两列
ax1.plot(np.random.rand(10))
ax1.set_title('Span Two Columns')

ax2 = fig.add_subplot(gs[0, 2])  # 第一行,第三列
ax2.scatter(np.random.rand(10), np.random.rand(10))
ax2.set_title('Single Column')

ax3 = fig.add_subplot(gs[1, :])  # 第二行,所有列
ax3.bar(range(10), np.random.rand(10))
ax3.set_title('Span All Columns')

plt.tight_layout()
plt.show()

2.5 图表定制

Matplotlib提供了丰富的选项来定制图表的外观。

# 设置样式
plt.style.use('seaborn-darkgrid')  # 使用预定义样式

# 创建数据
x = np.linspace(0, 10, 100)
y = np.sin(x)

# 创建图表
fig, ax = plt.subplots(figsize=(10, 6))

# 绘制数据
ax.plot(x, y, linewidth=2, color='#1E88E5', linestyle='-', 
        marker='o', markersize=6, markevery=10, 
        markerfacecolor='white', markeredgecolor='#1E88E5')

# 设置标题和标签
ax.set_title('Customized Sine Wave', fontsize=16, fontweight='bold')
ax.set_xlabel('X-axis', fontsize=12)
ax.set_ylabel('Y-axis', fontsize=12)

# 设置刻度
ax.tick_params(axis='both', which='major', labelsize=10)

# 设置网格
ax.grid(True, linestyle='--', alpha=0.7)

# 设置图例
ax.legend(['Sine Wave'], loc='upper right', frameon=True, shadow=True)

# 设置坐标轴范围
ax.set_xlim(0, 10)
ax.set_ylim(-1.5, 1.5)

# 添加水平和垂直线
ax.axhline(y=0, color='gray', linestyle='-', alpha=0.3)
ax.axvline(x=5, color='gray', linestyle='-', alpha=0.3)

# 添加文本注释
ax.annotate('Maximum', xy=(1.5, 1.0), xytext=(2, 1.3),
            arrowprops=dict(facecolor='black', shrink=0.05, width=1.5))

# 添加文本
ax.text(7, -1, 'Sine Wave Example', fontsize=12, style='italic')

# 设置背景色
ax.set_facecolor('#f8f9fa')

# 设置图表边框
for spine in ax.spines.values():
    spine.set_linewidth(1.5)
    
# 调整布局
plt.tight_layout()

# 显示图表
plt.show()

2.6 保存和导出

Matplotlib支持多种格式的图表导出。

# 创建简单图表
plt.figure(figsize=(8, 6))
plt.plot([1, 2, 3, 4], [10, 20, 25, 30], 'bo-')
plt.title('Simple Plot')

# 保存为不同格式
plt.savefig('plot.png', dpi=300)  # PNG格式,300 DPI
plt.savefig('plot.pdf')  # PDF格式
plt.savefig('plot.svg')  # SVG格式
plt.savefig('plot.jpg', quality=95)  # JPEG格式,95%质量

# 保存时设置透明背景
plt.savefig('plot_transparent.png', transparent=True)

# 保存时裁剪空白边缘
plt.savefig('plot_tight.png', bbox_inches='tight')

plt.show()

3. Seaborn基础

3.1 Seaborn简介

Seaborn是基于Matplotlib的统计数据可视化库,提供了更高级的接口和美观的默认样式。

Seaborn的优势

  • 美观的默认样式
  • 内置调色板系统
  • 支持统计估计和可视化
  • 与Pandas无缝集成
  • 简化复杂图表的创建
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# 设置样式
sns.set_theme(style="whitegrid")

# 创建示例数据
tips = sns.load_dataset("tips")

# 查看数据
print(tips.head())

# 简单的散点图
plt.figure(figsize=(10, 6))
sns.scatterplot(x="total_bill", y="tip", data=tips)
plt.title("Scatter Plot of Tips vs Total Bill")
plt.show()

3.2 Seaborn绘图函数

Seaborn提供了多种绘图函数,可以分为三类:

  • 关系图(Relational plots)
  • 分布图(Distribution plots)
  • 分类图(Categorical plots)
3.2.1 关系图

关系图用于可视化两个变量之间的关系。

# 散点图
plt.figure(figsize=(10, 6))
sns.scatterplot(x="total_bill", y="tip", hue="sex", style="smoker", size="size", data=tips)
plt.title("Scatter Plot with Multiple Dimensions")
plt.show()

# 线图
flights = sns.load_dataset("flights")
flights_pivot = flights.pivot(index="month", columns="year", values="passengers")

plt.figure(figsize=(12, 6))
sns.lineplot(data=flights_pivot)
plt.title("Passenger Numbers Over Time")
plt.show()

# 关系图
plt.figure(figsize=(10, 6))
sns.relplot(x="total_bill", y="tip", hue="sex", col="time", row="smoker", data=tips)
plt.show()
3.2.2 分布图

分布图用于可视化单变量或双变量分布。

# 直方图
plt.figure(figsize=(10, 6))
sns.histplot(data=tips, x="total_bill", hue="sex", multiple="stack")
plt.title("Distribution of Total Bill")
plt.show()

# 核密度估计图
plt.figure(figsize=(10, 6))
sns.kdeplot(data=tips, x="total_bill", hue="sex", fill=True)
plt.title("Density of Total Bill")
plt.show()

# 联合分布图
plt.figure(figsize=(10, 10))
sns.jointplot(x="total_bill", y="tip", data=tips, kind="hex")
plt.show()

# 成对关系图
sns.pairplot(tips, hue="sex")
plt.show()
3.2.3 分类图

分类图用于可视化分类变量与数值变量之间的关系。

# 箱线图
plt.figure(figsize=(10, 6))
sns.boxplot(x="day", y="total_bill", hue="sex", data=tips)
plt.title("Box Plot of Total Bill by Day and Sex")
plt.show()

# 小提琴图
plt.figure(figsize=(10, 6))
sns.violinplot(x="day", y="total_bill", hue="sex", data=tips, split=True)
plt.title("Violin Plot of Total Bill by Day and Sex")
plt.show()

# 条形图
plt.figure(figsize=(10, 6))
sns.barplot(x="day", y="total_bill", hue="sex", data=tips)
plt.title("Bar Plot of Average Total Bill by Day and Sex")
plt.show()

# 计数图
plt.figure(figsize=(10, 6))
sns.countplot(x="day", hue="sex", data=tips)
plt.title("Count of Visits by Day and Sex")
plt.show()

# 点图
plt.figure(figsize=(10, 6))
sns.pointplot(x="day", y="total_bill", hue="sex", data=tips)
plt.title("Point Plot of Average Total Bill by Day and Sex")
plt.show()

3.3 高级统计图表

Seaborn提供了多种高级统计图表,用于可视化复杂的统计关系。

# 回归图
plt.figure(figsize=(10, 6))
sns.regplot(x="total_bill", y="tip", data=tips)
plt.title("Regression Plot of Tip vs Total Bill")
plt.show()

# 残差图
plt.figure(figsize=(10, 6))
sns.residplot(x="total_bill", y="tip", data=tips)
plt.title("Residual Plot of Tip vs Total Bill")
plt.show()

# 热图
flights_pivot = flights.pivot(index="month", columns="year", values="passengers")
plt.figure(figsize=(12, 8))
sns.heatmap(flights_pivot, annot=True, fmt="d", cmap="YlGnBu")
plt.title("Heatmap of Passenger Numbers")
plt.show()

# 聚类图
sns.clustermap(flights_pivot, cmap="YlGnBu", standard_scale=1)
plt.title("Clustered Heatmap of Passenger Numbers")
plt.show()

3.4 FacetGrid和多图布局

Seaborn的FacetGrid允许在数据子集上创建多个图表。

# FacetGrid示例
g = sns.FacetGrid(tips, col="time", row="sex", height=4, aspect=1.5)
g.map_dataframe(sns.scatterplot, x="total_bill", y="tip")
g.add_legend()
plt.show()

# 使用catplot创建分类图的网格
sns.catplot(x="day", y="total_bill", hue="sex", col="time", data=tips, kind="box", height=4, aspect=1.5)
plt.show()

# 使用relplot创建关系图的网格
sns.relplot(x="total_bill", y="tip", hue="day", col="time", row="sex", data=tips, height=4)
plt.show()

3.5 主题和样式定制

Seaborn提供了多种主题和样式选项,可以轻松定制图表的外观。

# 设置样式
sns.set_style("whitegrid")  # 其他选项: darkgrid, white, dark, ticks

# 设置上下文
sns.set_context("notebook")  # 其他选项: paper, talk, poster

# 设置调色板
sns.set_palette("Set2")  # 其他选项: deep, muted, pastel, bright, dark, colorblind

# 创建自定义调色板
custom_palette = sns.color_palette("husl", 8)
sns.set_palette(custom_palette)

# 示例图表
plt.figure(figsize=(10, 6))
sns.boxplot(x="day", y="total_bill", hue="time", data=tips)
plt.title("Box Plot with Custom Style")
plt.show()

# 循环显示所有可用样式
styles = ['darkgrid', 'whitegrid', 'dark', 'white', 'ticks']
fig, axes = plt.subplots(nrows=len(styles), figsize=(8, 12))

for ax, style in zip(axes, styles):
    sns.set_style(style)
    sns.lineplot(x="total_bill", y="tip", data=tips, ax=ax)
    ax.set_title(f"Style: {style}")

plt.tight_layout()
plt.show()

4. 数据可视化最佳实践

4.1 选择合适的图表类型

选择合适的图表类型是有效数据可视化的关键。

数据类型目的推荐图表类型
时间序列显示趋势线图、面积图
分类比较比较不同类别柱状图、点图
部分与整体显示组成饼图、堆叠柱状图
分布显示数据分布直方图、箱线图、小提琴图
相关性显示变量关系散点图、热图、回归图
地理数据显示空间分布地图、等值线图
网络关系显示连接网络图、树图
# 数据类型与图表类型示例
np.random.seed(42)

# 创建示例数据
dates = pd.date_range('2023-01-01', periods=30)
time_series = pd.Series(np.cumsum(np.random.randn(30)), index=dates)
categories = ['A', 'B', 'C', 'D', 'E']
values = np.random.randint(10, 100, size=5)
distribution = np.random.normal(0, 1, 1000)
x = np.random.rand(50)
y = x + np.random.normal(0, 0.2, 50)

# 创建多个子图
fig, axes = plt.subplots(2, 3, figsize=(18, 10))

# 时间序列 - 线图
axes[0, 0].plot(time_series)
axes[0, 0].set_title('Time Series - Line Plot')

# 分类比较 - 柱状图
axes[0, 1].bar(categories, values)
axes[0, 1].set_title('Categorical Comparison - Bar Plot')

# 部分与整体 - 饼图
axes[0, 2].pie(values, labels=categories, autopct='%1.1f%%')
axes[0, 2].set_title('Part-to-Whole - Pie Chart')

# 分布 - 直方图
axes[1, 0].hist(distribution, bins=30)
axes[1, 0].set_title('Distribution - Histogram')

# 相关性 - 散点图
axes[1, 1].scatter(x, y)
axes[1, 1].set_title('Correlation - Scatter Plot')

# 相关性 - 热图
corr_matrix = np.corrcoef(np.random.rand(5, 5))
im = axes[1, 2].imshow(corr_matrix, cmap='coolwarm')
axes[1, 2].set_title('Correlation - Heatmap')
fig.colorbar(im, ax=axes[1, 2])

plt.tight_layout()
plt.show()

4.2 可视化设计原则

有效的数据可视化应遵循以下设计原则:

清晰性

  • 确保图表传达的信息清晰明确
  • 避免不必要的装饰和干扰元素
  • 使用适当的标题、标签和图例

简洁性

  • 保持简单,避免过度复杂
  • 移除不必要的元素(图表垃圾)
  • 每个图表专注于一个或少数几个关键信息

准确性

  • 确保数据表示准确无误
  • 避免扭曲或误导性的表示
  • 适当使用坐标轴(考虑是否从零开始)

有效性

  • 选择最适合数据和目的的图表类型
  • 考虑受众的需求和背景
  • 确保图表能够回答关键问题

一致性

  • 在多个图表中保持一致的样式和格式
  • 使用一致的配色方案和符号
  • 保持标签和术语的一致性

4.3 常见可视化错误

避免以下常见的可视化错误:

不恰当的图表类型

  • 使用饼图比较不相关的数据
  • 使用3D图表展示2D数据
  • 对时间序列数据使用散点图而非线图

误导性的缩放

  • Y轴不从零开始(在某些情况下)
  • 不成比例的轴缩放
  • 截断轴以夸大差异

过度复杂

  • 在一个图表中显示过多信息
  • 使用不必要的装饰和效果
  • 过度使用颜色和标记

颜色使用不当

  • 使用难以区分的颜色
  • 忽略色盲友好性
  • 颜色与数据无关的映射

缺乏上下文

  • 没有适当的标题和标签
  • 缺少单位或参考点
  • 没有解释异常值或重要特征

4.4 交互式可视化

交互式可视化允许用户探索和操作数据,提供更丰富的体验。

# 使用Plotly创建交互式图表
import plotly.express as px
import plotly.graph_objects as go

# 加载示例数据
df = px.data.gapminder()
df_2007 = df.query("year == 2007")

# 创建交互式散点图
fig = px.scatter(
    df_2007, 
    x="gdpPercap", 
    y="lifeExp", 
    size="pop", 
    color="continent",
    hover_name="country", 
    log_x=True, 
    size_max=60,
    title="GDP vs Life Expectancy (2007)"
)

# 添加悬停信息
fig.update_traces(
    hovertemplate="<b>%{hovertext}</b><br>GDP per Capita: %{x:$,.0f}<br>Life Expectancy: %{y:.1f} years<br>Population: %{marker.size:,}"
)

# 更新布局
fig.update_layout(
    xaxis_title="GDP per Capita (log scale)",
    yaxis_title="Life Expectancy (years)",
    legend_title="Continent"
)

# 显示图表
fig.show()

# 创建交互式时间序列动画
fig = px.scatter(
    df, 
    x="gdpPercap", 
    y="lifeExp", 
    size="pop", 
    color="continent",
    hover_name="country", 
    log_x=True, 
    size_max=60,
    animation_frame="year",
    title="GDP vs Life Expectancy (1952-2007)"
)

fig.update_layout(
    xaxis_title="GDP per Capita (log scale)",
    yaxis_title="Life Expectancy (years)",
    legend_title="Continent"
)

fig.show()

5. 从JAVA开发者视角理解数据可视化

5.1 概念对应关系

JAVA概念Python可视化概念
JFreeChart/JavaFXMatplotlib/Seaborn
Graphics2DMatplotlib Artist
JFrame/PanelFigure/Axes
Event Handlers交互式回调
Swing组件Matplotlib widgets
自定义渲染器自定义样式和格式化

5.2 编程范式对比

JAVA可视化编程

  • 面向对象,显式创建和管理组件
  • 事件驱动模型
  • 冗长但类型安全
  • 需要大量样板代码

Python可视化编程

  • 函数式和面向对象混合
  • 声明式API(特别是高级库)
  • 简洁但可能类型不安全
  • 更少的样板代码

5.3 工作流对比

JAVA可视化工作流

  1. 创建数据模型
  2. 设计图表类型和布局
  3. 配置渲染器和格式化器
  4. 添加交互性(如需要)
  5. 集成到应用程序中

Python可视化工作流

  1. 准备数据(通常使用Pandas)
  2. 选择图表类型和库
  3. 创建基本图表
  4. 定制和美化
  5. 保存或展示结果

5.4 实现对比

JAVA实现热图

// JAVA使用JFreeChart创建热图
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYBlockRenderer;
import org.jfree.data.xy.DefaultXYZDataset;

import java.awt.*;
import java.io.File;
import java.io.IOException;

public class HeatmapExample {
    public static void main(String[] args) {
        // 创建数据集
        DefaultXYZDataset dataset = new DefaultXYZDataset();
        double[][] data = new double[3][25];
        
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < 5; j++) {
                int index = i * 5 + j;
                data[0][index] = i;  // X
                data[1][index] = j;  // Y
                data[2][index] = Math.random();  // Z (value)
            }
        }
        
        dataset.addSeries("Series 1", data);
        
        // 创建图表
        JFreeChart chart = ChartFactory.createScatterPlot(
            "Heatmap Example",  // 标题
            "X",                // x轴标签
            "Y",                // y轴标签
            dataset             // 数据集
        );
        
        // 配置为热图
        XYPlot plot = (XYPlot) chart.getPlot();
        XYBlockRenderer renderer = new XYBlockRenderer();
        renderer.setBlockWidth(1.0);
        renderer.setBlockHeight(1.0);
        
        // 设置颜色渐变
        renderer.setPaintScale(new GradientPaintScale(0, 1, 
            new Color(0, 0, 255), new Color(255, 0, 0)));
        
        plot.setRenderer(renderer);
        
        // 保存图表
        try {
            ChartUtils.saveChartAsPNG(new File("heatmap.png"), chart, 500, 400);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    // 简化的渐变色标尺实现
    static class GradientPaintScale implements PaintScale {
        private final double lowerBound;
        private final double upperBound;
        private final Color lowerColor;
        private final Color upperColor;
        
        public GradientPaintScale(double lower, double upper, 
                                 Color lowerColor, Color upperColor) {
            this.lowerBound = lower;
            this.upperBound = upper;
            this.lowerColor = lowerColor;
            this.upperColor = upperColor;
        }
        
        @Override
        public double getLowerBound() {
            return lowerBound;
        }
        
        @Override
        public double getUpperBound() {
            return upperBound;
        }
        
        @Override
        public Paint getPaint(double value) {
            double ratio = (value - lowerBound) / (upperBound - lowerBound);
            ratio = Math.max(0.0, Math.min(1.0, ratio));
            
            int r = (int) (lowerColor.getRed() + ratio * 
                          (upperColor.getRed() - lowerColor.getRed()));
            int g = (int) (lowerColor.getGreen() + ratio * 
                          (upperColor.getGreen() - lowerColor.getGreen()));
            int b = (int) (lowerColor.getBlue() + ratio * 
                          (upperColor.getBlue() - lowerColor.getBlue()));
            
            return new Color(r, g, b);
        }
    }
}

Python实现热图

# Python使用Seaborn创建热图
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np

# 创建数据
data = np.random.rand(5, 5)

# 创建热图
plt.figure(figsize=(8, 6))
sns.heatmap(data, annot=True, cmap='coolwarm', linewidths=.5)
plt.title('Heatmap Example')
plt.savefig('heatmap.png')
plt.show()

6. 实践练习

练习1:基本绘图

  1. 创建一个包含线图、散点图和柱状图的图表
  2. 添加适当的标题、标签和图例
  3. 自定义颜色和样式
  4. 保存为高质量图像

练习2:数据可视化

  1. 加载一个真实数据集(如Titanic或Iris数据集)
  2. 创建至少3种不同类型的可视化来探索数据
  3. 使用Seaborn的高级功能创建一个多变量分析图表
  4. 解释每个可视化揭示的数据洞见

练习3:交互式仪表板

  1. 使用Plotly创建一个简单的交互式仪表板
  2. 包含至少3个不同类型的图表
  3. 添加交互元素(如悬停信息、缩放、过滤器)
  4. 导出为HTML文件以便共享

7. 总结与反思

  • 数据可视化是数据分析和机器学习中不可或缺的一部分,帮助理解数据和传达结果
  • Matplotlib提供了强大的底层绘图功能,适合创建自定义和精确控制的可视化
  • Seaborn建立在Matplotlib之上,提供了更高级的统计图表和美观的默认样式
  • 选择合适的图表类型和遵循可视化设计原则对于有效传达信息至关重要
  • 相比JAVA的可视化库,Python的可视化生态系统更加丰富和易用,特别适合数据科学和机器学习领域
  • 交互式可视化提供了更丰富的数据探索体验,适合创建仪表板和Web应用

8. 预习与延伸阅读

预习内容

  • PyTorch基础概念和张量操作
  • 神经网络的构建和训练流程
  • 常见的神经网络层和激活函数
  • 损失函数和优化器

延伸阅读

  1. Jake VanderPlas,《Python Data Science Handbook》(第4章和第5章)
  2. Claus O. Wilke,《Fundamentals of Data Visualization》
  3. Edward R. Tufte,《The Visual Display of Quantitative Information》
  4. Matplotlib官方文档:matplotlib.org/stable/tuto…
  5. Seaborn官方文档:seaborn.pydata.org/tutorial.ht…

9. 明日预告

明天我们将开始学习PyTorch基础,这是一个流行的深度学习框架。我们将探讨PyTorch的核心概念、张量操作、自动微分机制,以及如何构建和训练简单的神经网络模型。这些知识将为后续学习大模型开发奠定基础。