DAY 9 热力图和子图的绘制 -2025.8.19

热力图和子图的绘制

知识点:热力图和子图的绘制
1.介绍了热力图的绘制方法
2.介绍了enumerate()函数
3.介绍了子图的绘制方法

作业:
尝试对着心脏病数据集绘制热力图和单特征分布的大图(包含几个子图)

笔记:

1. 热力图的绘制方法

热力图是通过颜色深浅来直观展示数据矩阵中数值大小的图表,常用语展示相关性矩阵、混淆矩阵等。在python中,常用的绘制库是seabornmatplotlib

绘制步骤

  1. 准备数据: 先通过corr()函数来计算数据集的相关系数矩阵,corr() 通常用于特征选择(分析自变量与因变量的相关性)、多重共线性检测(分析自变量之间的相关性)、探索数据中潜在的关联模式。corr()函数的参数说明如下:
  • method:指定相关系数的计算方法(默认 'pearson'):
    • 'pearson':皮尔逊相关系数(最常用,适用于线性相关)。
    • 'kendall':肯德尔等级相关系数(适用于有序分类数据)。
    • 'spearman':斯皮尔曼等级相关系数(适用于非线性或有序数据)。
  • min_periods:计算相关系数所需的最小非缺失值数量(默认 1)。
  • 结果解释:
    • 相关系数的取值范围是 [-1, 1]:
      • 接近 1:强正相关(一个变量增加,另一个变量也增加)。
      • 接近 -1:强负相关(一个变量增加,另一个变量减少)。
      • 接近 0:几乎无线性相关。
    • 对角线元素恒为 1(变量与自身的相关性)。
    • 矩阵是对称的(A与B的相关性 = B与A的相关性)
  • 注意事项:
    • corr() 会自动排除包含缺失值(NaN)的行 / 列(或根据min_periods调整)。
    • 相关系数仅衡量线性关系,无法捕捉非线性关联(如二次关系)。
    • 相关性不等于因果关系,需结合业务逻辑解读结果。
  1. 使用seaborn绘制

    示例代码:

import seaborn as sns
import matplotlib.pyplot as plt

sns.heatmap(data,  # 数据矩阵
            cmap="YlGnBu",  # 颜色映射(如"viridis"、"coolwarm")
            annot=True,  # 是否在单元格中显示数值
            fmt=".2f",  # 数值格式(保留2位小数)
            linewidths=.5)  # 单元格边框宽度
plt.title("热力图示例")
plt.show()
  • 应用场景:
    • 相关性分析(如特征间的相关系数矩阵)
    • 数据分布可视化(如不同时间段的数值变化)

2. enumerate()函数

enumerate()是 Python 内置函数,用于将可迭代对象(如列表、元组)转换为枚举对象,同时返回元素的索引,简化了 “遍历元素并记录位置” 的操作。
语法:

enumerate(iterable, start=0)
  • iterable:需遍历的可迭代对象(如列表、字符串)。
  • start:索引的起始值(默认从 0 开始)。
    优势:
  • 避免手动定义计数器(如 i = 0; for value in iterable: ...; i += 1),代码更简洁。
  • 适用于需要同时获取元素位置和值的场景(如遍历列表并修改指定索引的元素)。

3. 子图的绘制方法

子图(Subplot)是在同一画布上绘制多个图表,便于对比数据。常用matplotlibplt.subplots()——一次性创建多个子图或plt.subplot()——逐个创建子图实现。

方法一:plt.subplots ()
语法:

fig, axes = plt.subplots(nrows, ncols, figsize=(,))
  • nrows:子图行数;ncols:子图列数。
  • fig:画布对象;axes:子图数组(若单图则为单个对象)。

示例代码:

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = x**2
y4 = np.exp(x)

# 创建2行2列的子图,画布大小10x8
fig, axes = plt.subplots(2, 2, figsize=(10, 8))

# 第1行第1列子图(索引[0,0])
axes[0, 0].plot(x, y1)
axes[0, 0].set_title("sin(x)")

# 第1行第2列子图(索引[0,1])
axes[0, 1].plot(x, y2, color="orange")
axes[0, 1].set_title("cos(x)")

# 第2行第1列子图(索引[1,0])
axes[1, 0].plot(x, y3, color="green")
axes[1, 0].set_title("x²")

# 第2行第2列子图(索引[1,1])
axes[1, 1].plot(x, y4, color="red")
axes[1, 1].set_title("e^x")

plt.tight_layout()  # 自动调整子图间距,避免重叠
plt.show()

方法二:plt.subplot ()
语法:

plt.subplot(nrows, ncols, index)  # index从1开始,按行优先排序

示例代码:

plt.subplot(1, 2, 1)  # 第1个位置(1行2列中的第1个)
plt.plot(x, y1)
plt.title("图1")

plt.subplot(1, 2, 2)  # 第2个位置
plt.plot(x, y2)
plt.title("图2")

plt.tight_layout()
plt.show()

注意事项:

  • 子图索引在subplots()中是0 开始的数组索引,在subplot()中是1 开始的位置编号
  • 使用plt.tight_layout()可避免子图标题、标签重叠。
  • 可通过axes对象单独设置每个子图的标题(set_title())、坐标轴标签(set_xlabel())等。

作业

心脏病数据集绘制热力图和单特征分布的大图(包含几个子图)

主要步骤如下:

  1. 数据导入和认识数据
  2. 绘制热力图
    1. 计算不同特征之间的皮尔逊相关系数,得到相关系数矩阵
    2. 导入绘图包,绘图
  3. 绘制单特征分布图
    1. 定义要绘制的特征
    2. 设置图片清晰度
    3. 创建子图布局
    4. 遍历特征并绘图
    5. 调整子图之间的间距
1. 数据导入和认识数据
import pandas as pd 
data = pd.read_csv(r'heart.csv')

data.info()

在这里插入图片描述
没有缺失值,不需要填补缺失值,不需要做类型转换,直接进行画图

2. 绘制热力图
1. 计算不同特征之间的皮尔逊相关系数,得到相关系数矩阵
2. 导入绘图包,绘图

1. 计算相关系数矩阵

## 绘制热力图
## 导入包
import seaborn as sns
import matplotlib.pyplot as plt

## 计算相关系数矩阵
corr_matrix = data.corr()
corr_matrix

在这里插入图片描述

2. 绘图

## 绘图
plt.figure(figsize=(12,10))  ## 新建画布
plt.rcParams['figure.dpi']=300 ##设置图片清晰度
sns.heatmap(corr_matrix,annot=True,cmap='coolwarm',vmin=-1,vmax=1)
plt.title('Correlation Heatmap of Features')
plt.show()

在这里插入图片描述

3. 绘制单特征分布图(包含多个子图)
1. 定义要绘制的特征
2. 设置图片清晰度
3. 创建子图布局
4. 遍历特征并绘图
5. 调整子图之间的间距
## 绘制子图
## 为了勤加练习,这里把特征分了三组,list1中储存了前6个列,list2中储存了后8列,list3中储存了全部的列
## 对list1,list2,list3 分别绘制子图

list1 = data.columns[0:6]  #取数据集中的列,从索引0取到索引6,不含索引6
list2 = data.columns[6:14]  #取数据集中的列,从索引6取到索引14
list3 = data.columns

print(list1,'\n',list2,'\n',list3)

在这里插入图片描述

## list1 绘制子图
## 创建画布,其中包含3行2列的子图
fig, axes = plt.subplots(3,2,figsize=(12,18))  
# 这里的axes是一个二维数组,包含2行2列的子图
# 这里的fig是一个Figure对象,表示整个图形窗口
# 你可以把fig想象成一个画布,axes就是在这个画布上画的图形

# 用for循环遍历所有特征并绘制小提琴图
for i,feature in enumerate(list1):
    row = i // 2
    col = i % 2 
    axes[row,col].violinplot(data[feature].dropna())
    axes[row,col].set_title(f"The ViolinPlot Of {feature}")
    axes[row,col].set_ylabel(feature)

# 调整子图之间的间距
plt.tight_layout()

#展示图形
plt.show()

在这里插入图片描述

## list2 绘制子图

fig , axes = plt.subplots(4,2,figsize=(12,24))

for i, feature in enumerate(list2):
    r = i // 2
    c = i % 2
    axes[r,c].violinplot(data[feature].dropna())
    axes[r,c].set_title(f'The ViolinPlot of {feature}')
    axes[r,c].set_ylabel(feature)

plt.tight_layout()
plt.show()

在这里插入图片描述

## list3 绘制子图

fig, axes = plt.subplots(7,2,figsize=(12,48))

for i,feature in enumerate(list3):
    r = i // 2
    c = i % 2 
    axes[r,c].violinplot(data[feature].dropna())
    axes[r,c].set_title(f'The Violinplot Of {feature}')
    axes[r,c].set_ylabel(feature)

plt.tight_layout()
plt.show()

在这里插入图片描述
@浙大疏锦行

import pandas as pd import tkinter as tk from tkinter import messagebox, ttk, filedialog from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg import matplotlib.pyplot as plt from matplotlib import font_manager from matplotlib.colors import Normalize # 新增这行 import seaborn as sns from scipy.ndimage import gaussian_filter import chardet import numpy as np # 新增导入 from matplotlib.colors import Normalize, LogNorm # 确保已导入 import re # 新增这行 import pandas as pd import tkinter as tk from tkinter import messagebox, ttk import traceback import re import pandas as pd def clean_time_input(time_str): """标准化时间输入格式为 YYYY/MM/DD HH:MM""" try: # 移除所有空格 time_str = time_str.replace(" ", "") # 匹配多种时间格式 match = re.match( r"(\d{4})[/-]?(\d{1,2})[/-]?(\d{1,2})[\sT]?(\d{1,2}:\d{2}|\d{4})", time_str ) if not match: raise ValueError("无法识别的时间格式") year, month, day, time = match.groups() # 处理时间部分(如果没冒号) if ":" not in time: time = f"{time[:2]}:{time[2:]}" # 补全前导零 month = month.zfill(2) day = day.zfill(2) return f"{year}/{month}/{day} {time}" except Exception as e: raise ValueError(f"时间处理失败: {str(e)}") # 创建主窗口 root = tk.Tk() root.title("电导率热力查询工具") root.geometry("800x700") root.minsize(700, 600) # 字体设置,确保SimHei.ttf在当前目录,解决中文乱码 my_font = font_manager.FontProperties(fname="SimHei.ttf") plt.rcParams[&#39;font.family&#39;] = my_font.get_name() plt.rcParams[&#39;axes.unicode_minus&#39;] = False # 检查并读取数据 # 在读取数据后添加检查代码 import chardet def detect_encoding(file_path): with open(file_path, &#39;rb&#39;) as f: result = chardet.detect(f.read()) return result[&#39;encoding&#39;] # 修改数据读取部分 # 检查并读取数据 try: encodings = { "新疆田1电导率.csv": detect_encoding("新疆田1电导率.csv"), "新疆田2电导率.csv": detect_encoding("新疆田2电导率.csv"), "新疆田3电导率.csv": detect_encoding("新疆田3电导率.csv"), "新疆田4电导率.csv": detect_encoding("新疆田4电导率.csv"), "新疆田5电导率.csv": detect_encoding("新疆田5电导率.csv"), "新疆田6电导率.csv": detect_encoding("新疆田6电导率.csv") } df_1 = pd.read_csv("新疆田1电导率.csv", encoding=encodings["新疆田1电导率.csv"]) df_2 = pd.read_csv("新疆田2电导率.csv", encoding=encodings["新疆田2电导率.csv"]) df_3 = pd.read_csv("新疆田3电导率.csv", encoding=encodings["新疆田3电导率.csv"]) df_4 = pd.read_csv("新疆田4电导率.csv", encoding=encodings["新疆田4电导率.csv"]) df_5 = pd.read_csv("新疆田5电导率.csv", encoding=encodings["新疆田5电导率.csv"]) df_6 = pd.read_csv("新疆田6电导率.csv", encoding=encodings["新疆田6电导率.csv"]) # 统一处理时间列 df_1[&#39;上报时间&#39;] = pd.to_datetime(df_1[&#39;上报时间&#39;]) df_2[&#39;上报时间&#39;] = pd.to_datetime(df_2[&#39;上报时间&#39;]) df_3[&#39;上报时间&#39;] = pd.to_datetime(df_3[&#39;上报时间&#39;]) df_4[&#39;上报时间&#39;] = pd.to_datetime(df_4[&#39;上报时间&#39;]) df_5[&#39;上报时间&#39;] = pd.to_datetime(df_5[&#39;上报时间&#39;]) df_6[&#39;上报时间&#39;] = pd.to_datetime(df_6[&#39;上报时间&#39;]) except FileNotFoundError as e: messagebox.showerror("文件错误", f"数据文件缺失: {e.filename}") root.quit() exit(1) depth_order = [&#39;d1&#39;, &#39;d2&#39;, &#39;d3&#39;, &#39;d4&#39;, &#39;d5&#39;, &#39;d6&#39;, &#39;d7&#39;, &#39;d8&#39;] depth_cm = { "d1": "10cm", "d2": "30cm", "d3": "50cm", "d4": "70cm", "d5": "90cm", "d6": "110cm", "d7": "130cm", "d8": "150cm" } # ========= 上方查询区 ========= frame_query = ttk.Frame(root, padding=10) frame_query.pack(fill=&#39;x&#39;) # 时间范围选择 frame_time = ttk.Frame(frame_query) frame_time.pack(side=&#39;left&#39;, padx=5) ttk.Label(frame_time, text="开始时间:", font=("微软雅黑", 11)).pack() entry_start = ttk.Entry(frame_time, width=20, font=("微软雅黑", 11)) entry_start.pack() entry_start.insert(0, "2025/6/30 17:00") ttk.Label(frame_time, text="结束时间:", font=("微软雅黑", 11)).pack() entry_end = ttk.Entry(frame_time, width=20, font=("微软雅黑", 11)) entry_end.pack() entry_end.insert(0, "2025/6/30 17:10") # 修改地块选择部分 frame_plot = ttk.Frame(frame_query) frame_plot.pack(side=&#39;left&#39;, padx=10) plot_vars = {} for i, plot_id in enumerate(["地块1", "地块2", "地块3", "地块4", "地块5", "地块6"]): var = tk.BooleanVar(value=True) plot_vars[plot_id] = var cb = ttk.Checkbutton(frame_plot, text=plot_id, variable=var) cb.grid(row=i//3, column=i%3, sticky=&#39;w&#39;) # 3列布局 # 操作按钮颜色选择 frame_buttons = ttk.Frame(frame_query) frame_buttons.pack(side=&#39;left&#39;, padx=10) btn_query = ttk.Button(frame_buttons, text="生成热力", width=15) btn_query.pack(pady=5) btn_save = ttk.Button(frame_buttons, text="保存表", width=15) btn_save.pack(pady=5) # 颜色映射选择 cmap_options = ["YlGn", "YlOrRd", "coolwarm", "viridis", "plasma", "magma"] cmap_var = tk.StringVar(value=cmap_options[0]) frame_cmap = ttk.Frame(frame_query) frame_cmap.pack(side=&#39;left&#39;, padx=10) ttk.Label(frame_cmap, text="颜色方案:").pack() cmap_menu = ttk.OptionMenu(frame_cmap, cmap_var, *cmap_options) cmap_menu.pack() # ========= 状态栏进度条 ========= status_frame = ttk.Frame(root) status_frame.pack(side=&#39;bottom&#39;, fill=&#39;x&#39;) status_var = tk.StringVar() status_var.set("请输入时间后点击生成热力") status_bar = ttk.Label(status_frame, textvariable=status_var, relief=&#39;sunken&#39;, anchor=&#39;w&#39;, padding=5) status_bar.pack(side=&#39;left&#39;, fill=&#39;x&#39;, expand=True) progress_var = tk.DoubleVar() progress_bar = ttk.Progressbar(status_frame, variable=progress_var, maximum=100) progress_bar.pack(side=&#39;right&#39;, fill=&#39;x&#39;, padx=5, pady=2, ipady=2) # ========= 表显示区 ========= frame_canvas = ttk.Frame(root) frame_canvas.pack(fill=&#39;both&#39;, expand=True, padx=10, pady=10) canvas_widget = None def extract_data(df, label): """从数据框中提取指定时间范围的数据""" global start_time, end_time # 使用全局时间变量 try: df_copy = df.copy() mask = (df_copy[&#39;上报时间&#39;] >= start_time) & (df_copy[&#39;上报时间&#39;] <= end_time) time_df = df_copy[mask] if time_df.empty: return None # 创建数据透视表 pivot = time_df.pivot_table( index=&#39;属性标识符&#39;, columns=&#39;设备名称&#39;, values=&#39;属性值&#39;, aggfunc=&#39;mean&#39; ) # 确保深度顺序一致 pivot = pivot.reindex(depth_order) pivot.columns = [label] return pivot except Exception as e: print(f"提取数据错误: {str(e)}") return None def save_plot(): if canvas_widget is None: messagebox.showwarning("警告", "没有可保存的表") return file_path = filedialog.asksaveasfilename( defaultextension=".png", filetypes=[("PNG 片", "*.png"), ("所有文件", "*.*")] ) if file_path: canvas_widget.figure.savefig(file_path, dpi=300) status_var.set(f"表已保存到: {file_path}") def show_heatmap(): global canvas_widget, start_time, end_time try: try: start_time = pd.to_datetime(clean_time_input(entry_start.get())) end_time = pd.to_datetime(clean_time_input(entry_end.get())) except ValueError as e: messagebox.showerror( "时间格式错误", f"请使用标准时间格式(如 2025/06/30 17:00)\n当前输入: {entry_start.get()}\n错误: {str(e)}" ) return # 检查时间顺序 if start_time > end_time: messagebox.showerror("时间错误", "开始时间不能晚于结束时间") return # 2. 检查地块选择(保留原逻辑) selected_plots = [k for k, v in plot_vars.items() if v.get()] if not selected_plots: messagebox.showwarning("警告", "请至少选择一个地块") return # 3. 数据提取处理(保留原逻辑) data_frames = [] plot_mapping = {"地块1": df_1, "地块2": df_2, "地块3": df_3, "地块4": df_4, "地块5": df_5, "地块6": df_6} for plot in selected_plots: df = extract_data(plot_mapping[plot], plot) if df is not None: data_frames.append(df) if not data_frames: messagebox.showinfo("无数据", "选定时间范围内没有数据") return combined = pd.concat(data_frames, axis=1) combined.index = [depth_cm.get(i, i) for i in combined.index] # 4. 可视化部分(使用您提供的新代码) fig, ax = plt.subplots(figsize=(10, 7)) combined_numeric = combined.apply(pd.to_numeric, errors=&#39;coerce&#39;) sns.heatmap( combined_numeric, annot=True, cmap=cmap_var.get(), fmt=".1f", cbar_kws={&#39;label&#39;: &#39;电导率 (μS/cm)&#39;}, ax=ax ) # 5. 显示表(保留原逻辑) for widget in frame_canvas.winfo_children(): widget.destroy() canvas_widget = FigureCanvasTkAgg(fig, master=frame_canvas) canvas_widget.draw() canvas_widget.get_tk_widget().pack(fill=&#39;both&#39;, expand=True) status_var.set("热力生成成功") except Exception as e: messagebox.showerror("生成错误", f"发生错误: {str(e)}") print(f"详细错误: {traceback.format_exc()}") def on_query_click(): show_heatmap() btn_query.config(command=on_query_click) btn_save.config(command=save_plot) # 支持回车查询滚轮调整 def on_mouse_wheel(event, entry): try: current_time = pd.to_datetime(entry.get()) if event.delta > 0: # 滚轮上滚 new_time = current_time + pd.Timedelta(days=1) direction = "前进" else: # 滚轮下滚 new_time = current_time - pd.Timedelta(days=1) direction = "后退" entry.delete(0, tk.END) entry.insert(0, new_time.strftime("%Y/%m/%d %H:%M")) status_var.set(f"时间调整: {direction} 1天 (当前: {new_time.strftime(&#39;%Y/%m/%d %H:%M&#39;)})") show_heatmap() # 自动更新热力 except: status_var.set("时间调整失败") entry_start.bind("<Return>", lambda event: on_query_click()) entry_start.bind("<MouseWheel>", lambda event: on_mouse_wheel(event, entry_start)) entry_end.bind("<Return>", lambda event: on_query_click()) entry_end.bind("<MouseWheel>", lambda event: on_mouse_wheel(event, entry_end)) # 添加必要的导入 from tkinter import filedialog # 设置关闭窗口时退出程序 root.protocol("WM_DELETE_WINDOW", root.quit) root.mainloop() 请你帮我优化这个代码,生成平滑的热力
07-26
### Java解析通达信 `.day` 文件数据格式示例 通达信的 `.day` 文件是一种二进制文件,主要用于存储股票的历史日线数据。下面详细介绍如何使用Java解析该文件,并提供完整的代码示例。 --- #### 1. 数据结构分析 每个记录占用 **32字节** 的空间,其字段分布如下表所示: | 字段名称 | 类型 | 占用字节数 | 描述 | |------------|-----------|-------------|----------------------------------------------------------------------| | 日期 | `int32` | 4 | 表示年月日组合成的一个整数,例如 `yyyyMMdd` 形式的数值[^1] | | 开盘价 | `float32` | 4 | 股票当天的开盘价格 | | 最高价 | `float32` | 4 | 当天交易过程中的最高价格 | | 最低价 | `float32` | 4 | 当天交易过程中的最低价格 | | 收盘价 | `float32` | 4 | 当天最后的收盘价格 | | 成交量 | `int32` | 4 | 当天总成交股份数 | | 储备字段1 | `int32` | 4 | 备用字段 | | 储备字段2 | `int32` | 4 | 备用字段 | --- #### 2. 示例代码 以下是一个完整的Java程序,用于解析通达信 `.day` 文件并输出其中的数据。 ```java import java.io.*; import java.nio.ByteBuffer; import java.nio.ByteOrder; public class TongDaXinDayParser { public static void main(String[] args) { // 替换为实际的 .day 文件路径 File dayFile = new File("path/to/s.day"); try (RandomAccessFile raf = new RandomAccessFile(dayFile, "r")) { long length = raf.length(); ByteBuffer buffer = ByteBuffer.allocate(32); buffer.order(ByteOrder.LITTLE_ENDIAN); // 设置小端模式 System.out.printf("%-10s%-10s%-10s%-10s%-10s%-10s%n", "Date", "Open", "High", "Low", "Close", "Volume"); while (raf.getFilePointer() < length) { byte[] bytes = new byte[buffer.capacity()]; raf.readFully(bytes); buffer.clear(); buffer.put(bytes).flip(); int date = buffer.getInt(); // 获取日期 float openPrice = buffer.getFloat(); // 获取开盘价 float highPrice = buffer.getFloat(); // 获取最高价 float lowPrice = buffer.getFloat(); // 获取最低价 float closePrice = buffer.getFloat(); // 获取收盘价 int volume = buffer.getInt(); // 获取成交量 // 忽略两个储备字段 buffer.position(buffer.limit()); // 格式化日期为 YYYY-MM-DD String formattedDate = formatDate(date); // 打印结果 System.out.printf("%-10s%-10.2f%-10.2f%-10.2f%-10.2f%-10d%n", formattedDate, openPrice, highPrice, lowPrice, closePrice, volume); } } catch (IOException e) { e.printStackTrace(); } } /** * 将日期从整数形式(yyyyMMdd)转换为字符串形式(YYYY-MM-DD) */ private static String formatDate(int dateInt) { int year = dateInt / 10000; int month = (dateInt % 10000) / 100; int day = dateInt % 100; return String.format("%d-%02d-%02d", year, month, day); } } ``` --- #### 3. 关键点说明 1. **小端模式**: 通达信 `.day` 文件采用的是小端模式存储数据,因此需要设置 `ByteOrder.LITTLE_ENDIAN`[^2]。 2. **日期解析**: 日期是以整数形式存储的,形如 `yyyyMMdd`。通过简单的算术操作即可拆分出具体的年、月、日[^1]。 3. **缓冲区管理**: 使用 `ByteBuffer` 来高效读取解析二进制数据,避免手动逐位计算偏移量带来的复杂性错误风险。 4. **忽略备用字段**: 后面的两个 `int32` 是备用字段,在大多数情况下不需要关注。 --- #### 4. 运行环境需求 - 确保运行环境中已安装JDK,并配置好开发工具链。 - 提供有效的 `.day` 文件路径作为输入参数。 - 注意不同操作系统之间的路径分隔符差异(Windows使用反斜杠 `\`,Linux/MacOS使用正斜杠 `/`)。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值