手把手教学滑动窗口

滑动窗口

滑动窗口主要思考以下几个问题

(1)当移动right应当更新什么数据

(2)什么条件下要停止扩大开始收缩left

(3)left缩小应该更新什么数据

(4)我们要的结果是在扩大时候更新还是缩小的时候更新

/*	滑动窗口算法框架	*/
void	slidingWindow(string	s,	string	t)	{
				unordered_map<char,int>	need,window;
				for	(char c:t)	need[c]++;
				int	left=0,	right=0;
				int	valid=0;	
				while	(right<	s.size())	{                //特别要注意的是,这里维持的是一个左闭右开的区间[left,right).因为终止边界上																//right==s.size()
					//c是将移入窗口的字符
					char c=s[right];
					//	右移窗口
					right++;
					//	进行窗口内数据的一系列更新
					...
					/***	debug	输出的位置	***/
					printf("window:	[%d,	%d)\n",	left,	right);
					/********************/
					//	判断左侧窗口是否要收缩
					while(window needs shrink)	{
					//	d	是将移出窗口的字符
					char d=s[left];
  					//	左移窗口
					left++;
					//	进行窗口内数据的一系列更新
												...
					}
			}
	}

调试很重要更加重要的是你要知道窗口维持的是一个左闭右开的这么一个区间(很重要的一个细节)

示例

leetcode 209题

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的连续子数组,并返回其长度。如果不存在符合条件的连续子数组,返回 0。

输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的连续子数组。
class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        //可以用滑动窗口和动态规划做
        //第一种解法:滑动窗口
        int n=nums.size();
        if(nums.empty()) return 0; //排除为空
        int len=0,left=0,right=0,sum=0;
        int res=INT_MAX;
        while(right<n)    //注意这里维持的是一个左闭右开的搜索窗口
        {
            int a=nums[right];
            right++;  
            sum+=a;     
            //窗口数据更新
            if(sum<s)
            {
                len=right-left;
            }
    
            //什么时候要收缩左边界
            while(sum>=s)    //代表找到了,这时候该缩小左边界,并且更新sum,和res
            {
                len=right-left;
                int b=nums[left];
                left++;
                sum-=b;
                res=min(res,len);
   
            }

        }
        return (res==INT_MAX)?0:res;   //这里判断是不是没有找到

    }
};
<think> 我们使用Biopython来处理基因组序列和特征,用Matplotlib进行绘图。以下是基本步骤: 1. **获取基因组序列和特征**:通常从GenBank文件中读取,Biopython的`SeqIO`和`Bio.Graphics`模块可以解析和绘制。 2. **创建图形和坐标轴**:使用Matplotlib创建图形和坐标轴对象。 3. **绘制基因结构**:遍历基因的特征(如基因、CDS、外显子、内含子),在染色体位置上用矩形或箭头表示。 4. **叠加GC含量分布**:将基因组序列分成窗口,计算每个窗口的GC含量,然后用折线图或面积图叠加。 5. **标记SNP/突变位点**:在对应的基因组位置上用垂直线或标记点表示。 具体步骤: **步骤1:导入库** ```python import matplotlib.pyplot as plt from Bio import SeqIO from Bio.SeqUtils import GC import numpy as np ``` **步骤2:读取GenBank文件** ```python record = SeqIO.read("genome.gb", "genbank") ``` **步骤3:提取基因特征并绘制** 我们将遍历记录中的特征(feature),根据特征类型(如'gene', 'CDS'等)进行绘制。 为了绘制基因结构,我们可以为每个特征绘制一个矩形(外显子)和连接线(内含子)。通常,基因用箭头表示方向。 这里我们用一个函数来绘制基因: ```python def draw_gene(ax, start, end, strand, y, height=0.4): """绘制一个基因,包括内含子和外显子""" # 绘制内含子(一条线) ax.plot([start, end], [y, y], 'k-', linewidth=1) # 绘制外显子(矩形) exon_width = min(50, (end - start) // 2) # 外显子宽度设为50bp或基因长度的一半(取较小者) if strand > 0: # 正链,箭头向右 ax.add_patch(plt.Rectangle((start, y-height/2), exon_width, height, facecolor='blue')) ax.arrow(start+exon_width, y, end - start - exon_width, 0, head_width=0.3, head_length=20, fc='blue', length_includes_head=True) else: # 负链,箭头向左 ax.add_patch(plt.Rectangle((end-exon_width, y-height/2), exon_width, height, facecolor='red')) ax.arrow(end-exon_width, y, -(end - start - exon_width), 0, head_width=0.3, head_length=20, fc='red', length_includes_head=True) ``` 注意:上述函数是一个简化示例,实际基因可能有多个外显子。因此,我们需要根据实际特征中的外显子位置逐个绘制。 对于具有多个外显子的基因,我们可以这样处理: ```python def draw_gene_with_exons(ax, feature, y, height=0.4): """绘制一个具有多个外显子的基因""" strand = feature.location.strand color = 'blue' if strand > 0 else 'red' # 获取外显子位置:GenBank文件中,CDS特征通常由多个位置组成(外显子) # 注意:有些基因特征可能没有子位置,我们可以用整个位置 if hasattr(feature.location, 'parts'): parts = feature.location.parts parts.sort(key=lambda x: x.start) # 确保按顺序 else: parts = [feature.location] # 绘制内含子(连接线) for i in range(len(parts)-1): start = parts[i].end end = parts[i+1].start ax.plot([start, end], [y, y], 'k-', linewidth=1) # 绘制每个外显子 for part in parts: start = part.start end = part.end ax.add_patch(plt.Rectangle((start, y-height/2), end-start, height, facecolor=color)) ``` 但是,请注意,GenBank文件中,一个基因(gene)特征可能只包含整个基因的范围,而外显子信息通常在mRNA或CDS特征中。因此,我们通常根据CDS特征来绘制外显子。 **因此,我们调整策略:直接遍历所有特征,根据特征类型分别绘制。** 我们可以这样做: - 遍历记录中的特征 - 如果是基因('gene'),我们只记录其位置和方向,用于标签 - 如果是CDS('CDS'),我们绘制外显子和内含子 **步骤4:计算GC含量滑动窗口** 我们将整个基因组序列分成多个窗口(例如每1000个碱基一个窗口),计算每个窗口的GC含量。 ```python window_size = 1000 step_size = 500 # 滑动步长 gc_values = [] positions = [] for start in range(0, len(record.seq) - window_size, step_size): end = start + window_size window = record.seq[start:end] gc_values.append(GC(window)) positions.append((start + end) // 2) # 窗口中心位置 ``` **步骤5:标记SNP/突变位点** 假设我们有一个SNP位置的列表(例如从VCF文件中读取),我们可以在图上用垂直线标记。 ```python snp_positions = [1000, 5000, 8000] # 示例SNP位置 ``` **步骤6:整合绘图** 创建一个图形,包含两个子图:一个用于显示基因结构,另一个用于显示GC含量(或者可以叠加到同一个图上,但使用不同的Y轴)。 这里我们创建两个子图,共享X轴: ```python fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(15, 10), sharex=True) ``` 在ax1上绘制基因结构,在ax2上绘制GC含量,并在ax1上标记SNP。 具体绘制: ```python # 绘制基因结构(在ax1上) y = 0 # 初始y坐标,每个基因可以设置不同的y值以避免重叠 for feature in record.features: if feature.type == 'gene': # 获取基因的位置和方向 start = feature.location.start end = feature.location.end strand = feature.location.strand # 绘制这个基因的整个范围(用线表示) ax1.plot([start, end], [y, y], 'k-', linewidth=1) # 绘制方向箭头 if strand > 0: ax1.arrow(start, y, 50, 0, head_width=0.1, head_length=30, fc='k') else: ax1.arrow(end, y, -50, 0, head_width=0.1, head_length=30, fc='k') # 标注基因名 if 'gene' in feature.qualifiers: gene_name = feature.qualifiers['gene'][0] ax1.text((start+end)/2, y+0.1, gene_name, ha='center') y += 1 # 下一个基因上移一行 # 但是,更详细的绘制应该针对CDS特征,显示外显子 # 我们可以重新遍历,针对CDS特征绘制外显子(在另一高度上) y_cds = 0 for feature in record.features: if feature.type == 'CDS': # 同样,我们为每个CDS分配一个y_cds,然后递增 if hasattr(feature.location, 'parts'): parts = feature.location.parts else: parts = [feature.location] # 排序 parts.sort(key=lambda x: x.start) # 绘制内含子连接线 for i in range(len(parts)-1): ax1.plot([parts[i].end, parts[i+1].start], [y_cds, y_cds], 'k-', linewidth=1) # 绘制外显子 for part in parts: ax1.add_patch(plt.Rectangle((part.start, y_cds-0.1), part.end-part.start, 0.2, facecolor='green')) y_cds += 1 # 绘制GC含量(在ax2上) ax2.plot(positions, gc_values, 'b-') ax2.set_ylabel('GC Content (%)') # 在ax1上标记SNP位置 for pos in snp_positions: ax1.axvline(x=pos, color='r', linestyle='--', alpha=0.5) # 也可以同时在ax2上标记 ax2.axvline(x=pos, color='r', linestyle='--', alpha=0.5) # 设置ax1的y轴范围,并隐藏y轴刻度(因为我们用高度代表不同基因,但刻度无实际意义) ax1.set_ylim(-1, max(y, y_cds)+1) ax1.set_yticks([]) # 隐藏y轴刻度 ax1.set_title('Gene Structure') ax2.set_title('GC Content') ax2.set_xlabel('Genome Position (bp)') plt.tight_layout() plt.show() ``` 注意:上述代码是一个简化的示例,实际应用中可能需要进行调整,例如处理多个基因重叠的情况(可能需要调整y坐标避免重叠)、颜色编码、图例等。 由于基因结构图可能比较复杂,建议使用专门用于基因组绘图的库(如`Bio.Graphics`模块中的`GenomeDiagram`)来绘制更专业的图形。但这里我们按照要求使用Matplotlib和Biopython的基本功能。 另外,如果基因数量很多,上述方法可能会显得拥挤,因此可能需要选择特定区域进行展示。 以上步骤提供了一个基本框架,具体实现时可能需要根据数据情况进行调整。 §§相关问题§§ 1. 如何从VCF文件中读取SNP位点并标记在图上? 2. 如何使用Biopython的GenomeDiagram模块绘制基因组图谱? 3. 如何调整图形以避免基因标签重叠? 4. 如何计算并绘制滑动GC含量? 5. 如果基因组很大,如何只绘制特定区域? </think> 下面我将详细介绍使用Matplotlib和BioPython进行基因组可视化的完整步骤,包括绘制基因结构、叠加GC含量分布和标记SNP位点。这个方法特别适合教学场景,能帮助学生直观理解基因组结构注释。 ### 基因组可视化基本步骤 #### 1. **准备环境和数据** ```python from Bio import SeqIO from Bio.SeqUtils import GC import matplotlib.pyplot as plt import numpy as np # 读取基因组文件(GenBank格式) record = SeqIO.read("genome.gb", "genbank") ``` #### 2. **绘制基因结构** ```python fig, ax = plt.subplots(figsize=(15, 8)) # 设置坐标轴 ax.set_xlim(0, len(record.seq)) ax.set_ylim(0, 5) ax.set_xlabel('基因组位置(bp)') ax.set_title('基因组结构注释可视化') # 遍历所有特征 for feature in record.features: start = feature.location.start end = feature.location.end strand = feature.location.strand # 绘制基因 if feature.type == "gene": y_level = 3 height = 0.3 ax.plot([start, end], [y_level, y_level], 'k-', lw=1.5) # 添加方向箭头 arrow_length = min(100, (end-start)//3) if strand > 0: # 正链 ax.arrow(end-arrow_length, y_level, arrow_length, 0, head_width=0.2, head_length=20, fc='blue') else: # 负链 ax.arrow(start+arrow_length, y_level, -arrow_length, 0, head_width=0.2, head_length=20, fc='red') # 绘制CDS(编码区) elif feature.type == "CDS": y_level = 2.5 height = 0.4 ax.add_patch(plt.Rectangle((start, y_level-height/2), end-start, height, facecolor='green', alpha=0.7)) # 绘制外显子 elif feature.type == "exon": y_level = 2 height = 0.3 ax.add_patch(plt.Rectangle((start, y_level-height/2), end-start, height, facecolor='purple', alpha=0.8)) # 绘制内含子 elif feature.type == "intron": y_level = 1.8 ax.plot([start, end], [y_level, y_level], 'k:', lw=1) ``` #### 3. **叠加GC含量分布** ```python # 计算滑动窗口GC含量 window_size = 500 step_size = 100 gc_values = [] positions = [] for start in range(0, len(record.seq) - window_size, step_size): end = start + window_size window_seq = record.seq[start:end] gc_values.append(GC(window_seq)) positions.append(start + window_size//2) # 创建双Y轴 ax_gc = ax.twinx() ax_gc.plot(positions, gc_values, 'b-', alpha=0.7) ax_gc.set_ylabel('GC含量(%)', color='b') ax_gc.tick_params(axis='y', labelcolor='b') ax_gc.set_ylim(30, 70) # 根据实际GC范围调整 ``` #### 4. **标记SNP/突变位点** ```python # 示例SNP位置 (实际可从VCF文件读取) snp_positions = [1500, 4500, 7800, 9200] for pos in snp_positions: ax.axvline(x=pos, color='r', linestyle='--', alpha=0.5) ax.text(pos, 4.5, 'SNP', rotation=90, ha='center', va='bottom', color='r') ``` #### 5. **添加图例和修饰** ```python # 添加图例 from matplotlib.patches import Patch legend_elements = [ Patch(facecolor='blue', label='基因(正链)'), Patch(facecolor='red', label='基因(负链)'), Patch(facecolor='green', label='CDS'), Patch(facecolor='purple', label='外显子'), plt.Line2D([0], [0], color='k', linestyle=':', label='内含子'), plt.Line2D([0], [0], color='r', linestyle='--', label='SNP位点') ] ax.legend(handles=legend_elements, loc='upper right') # 添加网格 ax.grid(True, linestyle='--', alpha=0.3) plt.tight_layout() plt.savefig('genome_visualization.png', dpi=300) plt.show() ``` ### 关键技巧说明 1. **分层绘制**:不同基因组元件使用不同Y轴高度,避免重叠 2. **方向表示**:使用箭头表示基因转录方向(蓝色→正链,红色←负链) 3. **GC计算优化**:滑动窗口大小影响曲线平滑度,教学场景推荐500-1000bp窗口 4. **交互式标记**:可添加鼠标悬停显示详细信息功能(使用`mplcursors`库) ### 教学应用建议 1. **逐步构建**:先展示基本基因结构,再逐步添加GC含量和SNP标记 2. **区域放大**:对特定基因区域进行缩放展示细节 3. **颜色编码**:使用统一颜色方案帮助学生快速识别元件类型 4. **真实案例**:使用学生研究项目的基因组数据作为示例 [^1]: 此方法结合了Biopython的基因组解析能力和Matplotlib的灵活可视化,特别适合教学演示。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值