FScanpy-package/FScanpy_Demo.ipynb

696 lines
72 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# FScanpy \n",
"\n",
"This notebook demonstrates how to use FScanpy with real test data for complete PRF site prediction analysis, including:\n",
"\n",
"## 🎯 Complete Workflow\n",
"1. **Load Test Data** - Use built-in real test data\n",
"2. **FScanR Analysis** - Identify potential PRF sites from BLASTX results\n",
"3. **Sequence Extraction** - Extract sequences around PRF sites\n",
"4. **FScanpy Prediction** - Use machine learning models to predict probabilities\n",
"5. **Results Visualization** - Generate prediction result plots using built-in plotting functions\n",
"6. **Sequence-level Prediction Demo** - Sliding window analysis of complete sequences\n",
"\n",
"## 📊 Data Description\n",
"- **blastx_example.xlsx**: Real BLASTX alignment results\n",
"- **mrna_example.fasta**: Real mRNA sequence data\n",
"- **region_example.csv**: Sample for individual site prediction"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📦 Environment Setup and Data Loading"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"ename": "ImportError",
"evalue": "cannot import name 'PRFPredictor' from 'FScanpy' (unknown location)",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[3], line 6\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mimport\u001b[39;00m \u001b[38;5;21;01mmatplotlib\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mpyplot\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m \u001b[38;5;21;01mplt\u001b[39;00m\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# Import FScanpy related modules\u001b[39;00m\n\u001b[0;32m----> 6\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mFScanpy\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m PRFPredictor, predict_prf, plot_prf_prediction\n\u001b[1;32m 7\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mFScanpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdata\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m get_test_data_path, list_test_data\n\u001b[1;32m 8\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mFScanpy\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m fscanr, extract_prf_regions\n",
"\u001b[0;31mImportError\u001b[0m: cannot import name 'PRFPredictor' from 'FScanpy' (unknown location)"
]
}
],
"source": [
"# Import necessary libraries\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# Import FScanpy related modules\n",
"from FScanpy import PRFPredictor, predict_prf, plot_prf_prediction\n",
"from FScanpy.data import get_test_data_path, list_test_data\n",
"from FScanpy.utils import fscanr, extract_prf_regions\n",
"\n",
"print(\"✅ Environment setup complete!\")\n",
"print(\"📋 Available test data:\")\n",
"list_test_data()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Load and Explore Test Data\n",
"\n",
"First, load the real test data provided by FScanpy to understand the data structure."
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"📁 数据文件路径:\n",
" BLASTX数据: /mnt/lmpbe/guest01/FScanpy-package-main/FScanpy/data/test_data/blastx_example.xlsx\n",
" mRNA序列: /mnt/lmpbe/guest01/FScanpy-package-main/FScanpy/data/test_data/mrna_example.fasta\n",
" 验证区域: /mnt/lmpbe/guest01/FScanpy-package-main/FScanpy/data/test_data/region_example.csv\n",
"\n",
"🧬 BLASTX数据概览:\n",
" 数据形状: (1000, 14)\n",
" 列名: ['DNA_seqid', 'Pep_seqid', 'pident', 'length', 'mismatch', 'gapopen', 'qstart', 'qend', 'sstart', 'send', 'evalue', 'bitscore', 'qframe', 'sframe']\n",
" 唯一序列数: 704\n",
"\n",
"📊 BLASTX数据示例:\n",
" DNA_seqid Pep_seqid pident length evalue qframe\n",
"0 MSTRG.9998.1 CAMPEP_0196994412 68.27 104 1.000000e-33 2\n",
"1 MSTRG.9996.1 CAMPEP_0197017426 49.16 297 3.000000e-79 2\n",
"2 MSTRG.9994.1 CAMPEP_0197009206 98.31 354 0.000000e+00 2\n",
"3 MSTRG.9993.1 CAMPEP_0168331218 51.67 60 2.000000e-37 2\n",
"4 MSTRG.9993.1 CAMPEP_0168331218 45.45 88 2.000000e-37 3\n"
]
}
],
"source": [
"# Get test data paths\n",
"blastx_file = get_test_data_path('blastx_example.xlsx')\n",
"mrna_file = get_test_data_path('mrna_example.fasta')\n",
"region_file = get_test_data_path('region_example.csv')\n",
"\n",
"print(f\"📁 Data file paths:\")\n",
"print(f\" BLASTX data: {blastx_file}\")\n",
"print(f\" mRNA sequences: {mrna_file}\")\n",
"print(f\" Validation regions: {region_file}\")\n",
"\n",
"# Load BLASTX data\n",
"blastx_data = pd.read_excel(blastx_file)\n",
"print(f\"\\n🧬 BLASTX data overview:\")\n",
"print(f\" Data shape: {blastx_data.shape}\")\n",
"print(f\" Column names: {list(blastx_data.columns)}\")\n",
"print(f\" Unique sequences: {blastx_data['DNA_seqid'].nunique()}\")\n",
"\n",
"# Display first few rows\n",
"print(\"\\n📊 BLASTX data examples:\")\n",
"display_cols = ['DNA_seqid', 'Pep_seqid', 'pident', 'length', 'evalue', 'qframe']\n",
"print(blastx_data[display_cols].head())"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🎯 验证区域数据概览:\n",
" 数据形状: (3, 8)\n",
" 列名: ['FS_period', '399bp', 'fs_position', 'DNA_seqid', 'label', 'source', 'FS_type', 'dataset']\n",
" 数据来源: {'EUPLOTES': 3}\n",
"\n",
"📋 验证区域数据示例:\n",
" fs_position DNA_seqid label source FS_type\n",
"0 16.0 MSTRG.18491.1 0 EUPLOTES negative\n",
"1 16.0 MSTRG.4662.1 0 EUPLOTES negative\n",
"2 16.0 MSTRG.14742.1 0 EUPLOTES negative\n",
"\n",
"📈 标签分布:\n",
"label\n",
"0 3\n",
"Name: count, dtype: int64\n",
"\n",
"🔬 FS类型分布:\n",
"FS_type\n",
"negative 3\n",
"Name: count, dtype: int64\n"
]
}
],
"source": [
"# Load validation region data\n",
"region_data = pd.read_csv(region_file)\n",
"print(f\"🎯 Validation region data overview:\")\n",
"print(f\" Data shape: {region_data.shape}\")\n",
"print(f\" Column names: {list(region_data.columns)}\")\n",
"print(f\" Data sources: {region_data['source'].value_counts().to_dict()}\")\n",
"\n",
"print(\"\\n📋 Validation region data examples:\")\n",
"display_cols = ['fs_position', 'DNA_seqid', 'label', 'source', 'FS_type']\n",
"print(region_data[display_cols].head())\n",
"\n",
"# Statistical analysis\n",
"print(f\"\\n📈 Label distribution:\")\n",
"print(region_data['label'].value_counts())\n",
"print(f\"\\n🔬 FS type distribution:\")\n",
"print(region_data['FS_type'].value_counts())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. FScanR Analysis - Identify Potential PRF Sites from BLASTX\n",
"\n",
"Use the FScanR algorithm to analyze BLASTX results and identify potential programmed ribosomal frameshift sites."
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🔍 运行FScanR分析...\n",
"参数设置: mismatch_cutoff=10, evalue_cutoff=1e-5, frameDist_cutoff=10\n",
"\n",
"✅ FScanR分析完成\n",
"检测到的潜在PRF位点数量: 24\n",
"\n",
"📊 FScanR结果概览:\n",
" 列名: ['DNA_seqid', 'FS_start', 'FS_end', 'Pep_seqid', 'Pep_FS_start', 'Pep_FS_end', 'FS_type', 'Strand']\n",
" 涉及的序列数: 16\n",
" 链方向分布: {'+': 16, '-': 8}\n",
" FS类型分布: {1: 16, -1: 7, -2: 1}\n",
"\n",
"🎯 FScanR结果示例:\n",
" DNA_seqid FS_start FS_end Pep_seqid Pep_FS_start \\\n",
"0 MSTRG.9380.1 3797 3802 CAMPEP_0197017206 1137 \n",
"1 MSTRG.9431.1 4136 4192 CAMPEP_0197016790 657 \n",
"3 MSTRG.9432.1 848 904 CAMPEP_0197016790 753 \n",
"4 MSTRG.9582.1 302 304 CAMPEP_0197003180 214 \n",
"5 MSTRG.961.1 1536 1533 CAMPEP_0197017908 590 \n",
"\n",
" Pep_FS_end FS_type Strand \n",
"0 1138 1 + \n",
"1 675 1 + \n",
"3 2 1 - \n",
"4 214 1 + \n",
"5 19 -1 - \n"
]
}
],
"source": [
"# Run FScanR analysis\n",
"print(\"🔍 Running FScanR analysis...\")\n",
"print(\"Parameter settings: mismatch_cutoff=10, evalue_cutoff=1e-5, frameDist_cutoff=100\")\n",
"\n",
"fscanr_results = fscanr(\n",
" blastx_data,\n",
" mismatch_cutoff=10,\n",
" evalue_cutoff=1e-5,\n",
" frameDist_cutoff=100\n",
")\n",
"\n",
"print(f\"\\n✅ FScanR analysis complete!\")\n",
"print(f\"Number of potential PRF sites detected: {len(fscanr_results)}\")\n",
"\n",
"if len(fscanr_results) > 0:\n",
" print(f\"\\n📊 FScanR results overview:\")\n",
" print(f\" Column names: {list(fscanr_results.columns)}\")\n",
" print(f\" Number of sequences involved: {fscanr_results['DNA_seqid'].nunique()}\")\n",
" print(f\" Strand orientation distribution: {fscanr_results['Strand'].value_counts().to_dict()}\")\n",
" print(f\" FS type distribution: {fscanr_results['FS_type'].value_counts().to_dict()}\")\n",
" \n",
" print(\"\\n🎯 FScanR results examples:\")\n",
" print(fscanr_results.head())\n",
"else:\n",
" print(\"⚠️ No PRF sites detected, may need to adjust parameters\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Sequence Extraction - Extract Sequences Around PRF Sites\n",
"\n",
"Extract sequence fragments around PRF sites identified by FScanR from mRNA sequences."
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"📝 从mRNA序列中提取PRF位点周围序列...\n",
"\n",
"✅ 序列提取完成!\n",
"成功提取的序列数量: 24\n",
"\n",
"📏 序列长度验证:\n",
" 399bp序列长度分布: {399: 24}\n",
" 平均长度: 399.0\n",
"\n",
"🧬 提取序列示例:\n",
"序列 1: MSTRG.9380.1\n",
" FS位置: 3797-3802\n",
" 链方向: +\n",
" FS类型: 1\n",
" 序列片段: AAGGAGTTTGAAGAAGAACAGGAAAAACAAGAGAAAGAGAGAAAGGAGAA...NNNNNNNNNNNNNNNNNNNN\n",
"\n",
"序列 2: MSTRG.9431.1\n",
" FS位置: 4136-4192\n",
" 链方向: +\n",
" FS类型: 1\n",
" 序列片段: CAAGTATCTGAGTGGGAGGGAGACACAGGTGTTGATCAAACCCCATTCCC...ATAATGACGGAGGCTTCAGA\n",
"\n",
"序列 3: MSTRG.9432.1\n",
" FS位置: 848-904\n",
" 链方向: -\n",
" FS类型: 1\n",
" 序列片段: AGAAAGGATGGTACTGAAAATCAACGAAGTACTTTCACATTTTAGAAAGA...GCTGAGAACGATATTGACAA\n",
"\n"
]
}
],
"source": [
"# Extract sequences around PRF sites\n",
"if len(fscanr_results) > 0:\n",
" print(\"📝 Extracting sequences around PRF sites from mRNA sequences...\")\n",
" \n",
" prf_sequences = extract_prf_regions(\n",
" mrna_file=mrna_file,\n",
" prf_data=fscanr_results\n",
" )\n",
" \n",
" print(f\"\\n✅ Sequence extraction complete!\")\n",
" print(f\"Number of successfully extracted sequences: {len(prf_sequences)}\")\n",
" \n",
" if len(prf_sequences) > 0:\n",
" print(f\"\\n📏 Sequence length validation:\")\n",
" seq_lengths = prf_sequences['399bp'].str.len()\n",
" print(f\" 399bp sequence length distribution: {seq_lengths.value_counts().to_dict()}\")\n",
" print(f\" Average length: {seq_lengths.mean():.1f}\")\n",
" \n",
" print(\"\\n🧬 Extracted sequence examples:\")\n",
" for i, row in prf_sequences.head(3).iterrows():\n",
" print(f\"Sequence {i+1}: {row['DNA_seqid']}\")\n",
" print(f\" FS position: {row['FS_start']}-{row['FS_end']}\")\n",
" print(f\" Strand orientation: {row['Strand']}\")\n",
" print(f\" FS type: {row['FS_type']}\")\n",
" print(f\" Sequence fragment: {row['399bp'][:50]}...{row['399bp'][-20:]}\")\n",
" print()\n",
" else:\n",
" print(\"❌ Sequence extraction failed\")\n",
"else:\n",
" print(\"⚠️ Skipping sequence extraction - no FScanR results\")\n",
" prf_sequences = pd.DataFrame()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. FScanpy Prediction - Machine Learning Model Analysis\n",
"\n",
"Use FScanpy's machine learning models to predict PRF probabilities for the extracted sequences."
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🤖 FScanpy预测器初始化完成\n",
"\n",
"🎯 对 24 个FScanR识别的序列进行预测...\n",
"\n",
"📊 FScanR+FScanpy预测结果:\n",
" DNA_seqid FS_start FS_type Short_Probability Long_Probability \\\n",
"0 MSTRG.9380.1 3797 1 0.239192 0.087024 \n",
"1 MSTRG.9431.1 4136 1 0.326807 0.356356 \n",
"2 MSTRG.9432.1 848 1 0.310908 0.159746 \n",
"3 MSTRG.9582.1 302 1 0.272451 0.223354 \n",
"4 MSTRG.961.1 1536 -1 0.263269 0.046773 \n",
"\n",
" Ensemble_Probability \n",
"0 0.147891 \n",
"1 0.344536 \n",
"2 0.220211 \n",
"3 0.242993 \n",
"4 0.133372 \n"
]
}
],
"source": [
"# Initialize predictor\n",
"predictor = PRFPredictor()\n",
"print(\"🤖 FScanpy predictor initialization complete\")\n",
"\n",
"# Predict FScanR identified sequences\n",
"if len(prf_sequences) > 0:\n",
" print(f\"\\n🎯 Predicting {len(prf_sequences)} sequences identified by FScanR...\")\n",
" \n",
" fscanr_predictions = predictor.predict_regions(\n",
" sequences=prf_sequences['399bp'],\n",
" ensemble_weight=0.4 # Balanced configuration\n",
" )\n",
" \n",
" # Merge results\n",
" fscanr_predictions = pd.concat([\n",
" prf_sequences.reset_index(drop=True),\n",
" fscanr_predictions.reset_index(drop=True)\n",
" ], axis=1)\n",
" \n",
" print(\"\\n📊 FScanR+FScanpy prediction results:\")\n",
" result_cols = ['DNA_seqid', 'FS_start', 'FS_type', 'Short_Probability', 'Long_Probability', 'Ensemble_Probability']\n",
" print(fscanr_predictions[result_cols].head())"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"🧪 对 3 个验证区域进行预测...\n",
"\n",
"📊 验证区域预测结果:\n",
" DNA_seqid label source Short_Probability Long_Probability \\\n",
"0 MSTRG.18491.1 0 EUPLOTES 0.368610 0.144442 \n",
"1 MSTRG.4662.1 0 EUPLOTES 0.229811 0.053352 \n",
"2 MSTRG.14742.1 0 EUPLOTES 0.454152 0.345118 \n",
"\n",
" Ensemble_Probability \n",
"0 0.234109 \n",
"1 0.123936 \n",
"2 0.388732 \n"
]
}
],
"source": [
"# Predict validation region data\n",
"print(f\"\\n🧪 Predicting {len(region_data)} validation regions...\")\n",
"\n",
"validation_predictions = predict_prf(\n",
" data=region_data.rename(columns={'399bp': 'Long_Sequence'}),\n",
" ensemble_weight=0.4\n",
")\n",
"\n",
"print(\"\\n📊 Validation region prediction results:\")\n",
"result_cols = ['DNA_seqid', 'label', 'source', 'Short_Probability', 'Long_Probability', 'Ensemble_Probability']\n",
"print(validation_predictions[result_cols].head())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. Sequence-level Prediction and Visualization\n",
"\n",
"Select a specific mRNA sequence and use the built-in plot_prf_prediction function for complete sliding window prediction and visualization."
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🧬 选择演示序列: MSTRG.9127.1\n",
"序列长度: 256 bp\n",
"序列前100bp: TGGCCTTCTTACTTGGAAGTCCCCAAGGATCATCTTGGCCATCCTTGCTTTCTTCATGGCTAGATTCTACCTCCTCCCATAATTGTGTGAAACAAGTAAC...\n",
"\n",
"🎯 使用plot_prf_prediction进行序列预测和可视化...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/mnt/lmpbe/guest01/FScanpy-package-main/FScanpy/predictor.py:335: UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect.\n",
" plt.tight_layout()\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 39044 (\\N{CJK UNIFIED IDEOGRAPH-9884}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 27979 (\\N{CJK UNIFIED IDEOGRAPH-6D4B}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 27010 (\\N{CJK UNIFIED IDEOGRAPH-6982}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 29575 (\\N{CJK UNIFIED IDEOGRAPH-7387}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 28909 (\\N{CJK UNIFIED IDEOGRAPH-70ED}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 22270 (\\N{CJK UNIFIED IDEOGRAPH-56FE}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 31227 (\\N{CJK UNIFIED IDEOGRAPH-79FB}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 30721 (\\N{CJK UNIFIED IDEOGRAPH-7801}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 20998 (\\N{CJK UNIFIED IDEOGRAPH-5206}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 24067 (\\N{CJK UNIFIED IDEOGRAPH-5E03}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 38598 (\\N{CJK UNIFIED IDEOGRAPH-96C6}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 25104 (\\N{CJK UNIFIED IDEOGRAPH-6210}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 26435 (\\N{CJK UNIFIED IDEOGRAPH-6743}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 37325 (\\N{CJK UNIFIED IDEOGRAPH-91CD}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 24207 (\\N{CJK UNIFIED IDEOGRAPH-5E8F}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 21015 (\\N{CJK UNIFIED IDEOGRAPH-5217}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 20301 (\\N{CJK UNIFIED IDEOGRAPH-4F4D}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 32622 (\\N{CJK UNIFIED IDEOGRAPH-7F6E}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 36807 (\\N{CJK UNIFIED IDEOGRAPH-8FC7}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 28388 (\\N{CJK UNIFIED IDEOGRAPH-6EE4}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 38408 (\\N{CJK UNIFIED IDEOGRAPH-9608}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 20540 (\\N{CJK UNIFIED IDEOGRAPH-503C}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 30340 (\\N{CJK UNIFIED IDEOGRAPH-7684}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 32467 (\\N{CJK UNIFIED IDEOGRAPH-7ED3}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 26524 (\\N{CJK UNIFIED IDEOGRAPH-679C}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 65288 (\\N{FULLWIDTH LEFT PARENTHESIS}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 26465 (\\N{CJK UNIFIED IDEOGRAPH-6761}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 24418 (\\N{CJK UNIFIED IDEOGRAPH-5F62}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n",
"/home/guest01/.conda/envs/tf200/lib/python3.9/site-packages/IPython/core/pylabtools.py:152: UserWarning: Glyph 65289 (\\N{FULLWIDTH RIGHT PARENTHESIS}) missing from font(s) Liberation Sans.\n",
" fig.canvas.print_figure(bytes_io, **kw)\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABRcAAALmCAYAAADYLKN3AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8ekN5oAAAACXBIWXMAAA9hAAAPYQGoP6dpAAB3P0lEQVR4nOzdd5hV1b0/4M8MvYmAHUUS7IgRG/ZCxBqCKd6AsSCxBcHY9UaNJvYoMYJ6FQtKNGo0Yosltti9RpMIErFiQ6IIDIq0YWZ+f/DjXMcBxA0yDL7v8+TJnHXWPuu798w65/hh7b3LampqagIAAAAA8BWV13cBAAAAAEDDJFwEAAAAAAoRLgIAAAAAhQgXAQAAAIBChIsAAAAAQCHCRQAAAACgEOEiAAAAAFCIcBEAAAAAKES4CAAAAAAU0ri+CwAAGpa//e1vufnmm2u1XXXVVRk9enQuv/zyWu3nnXdeOnTosMDXOeigg/L8889n0KBBGTx48AL79OnTJ+PGjcv555+fH/7wh6X2v/zlL/nTn/6UN954IxUVFWndunU23XTTHHnkkdlmm22SJD179syECRMWuS/zx55fy+eVlZWlbdu22WabbXLMMcdk/fXXr7P9gw8+mD/96U8ZO3ZsPv3007Rq1Spdu3bNj3/84+y7776LHDtJ/vnPf+aSSy7JSy+9lKZNm2bnnXfOL3/5yzrHbMqUKTnllFPyxBNP5Oqrr87OO+9c6/nKysrccMMNGTVqVCZMmJBVV101u+++e44++ui0bt36S4/HD37wg1xwwQWLrPX666/PxRdfnF69euWSSy5ZZN/bb789Dz30UOlxhw4dct555yVJTj311IwaNapW/yZNmmTttddO7969c/jhh6dp06ZJkmHDhuWyyy6r8/otW7bMJptskp/97Gfp2bNnqX1h/ef78Y9/nKOPPjq//vWva7Uff/zx6dy5c4455pha7f379892222XE044IdOnTy+1f+9730vv3r1z3nnn5Z133im1b7fddunfv3+GDx+eF198sdS+wQYb5IQTTljocVlac+qLvurrzp49e4HHZsMNN1ys8QCAbybhIgDwlbz//vs544wzsvbaaydJLrzwwiTJ5MmTM2DAgPTo0SNJcuONN2bmzJmLfK2WLVtm1KhRGTRoUMrKymo9N27cuLz77rt1trniiity2WWXZdCgQTnjjDPSsmXLvPvuu7nqqqvys5/9LCNHjkz37t1z++23p6qqqrTd97///fTo0SOnnXZarfHn69q1a6666qrS46qqqrz11lu55JJLcsABB+Suu+7KWmutlSSpqanJqaeemvvvvz8DBgzI8ccfn5VXXjkfffRR7rnnnpxwwgn5+9//nrPOOmuh+z5u3LgcfPDB2XHHHXPLLbeksrIyp5xySo466qjceuutKS+fd4LJ888/nxNOOCFt2rRZ6GtdeOGFue2223LmmWdmq622yssvv5wzzjgjH330UYYMGZIkdY5HkkydOjU/+clPst122y30tSsqKnLqqadm7Nixadas2UL7fd6bb75Z61jO/xuZr3379rn77rtLjz/55JM8++yzufjii/Pmm2/md7/7Xa3+jz76aClwrKmpyX/+85/84Q9/yMCBA3PZZZdl9913X2j/z2vRokU++OCD7LnnnqWw+rHHHktFRUXmzp2bTTfdtBR0v/baa3n55ZeTJKuttlrpOH722We57rrrkiSNGjVa4H5OnTp1ge0LOy5Lc0593ld93RkzZizw2AAALIpwEQCoN1tvvXWeeOKJPPfcc3UCrlGjRmXrrbfO448/Xqv9xhtvzL777puBAweW2tZaa61sscUWOfDAA/Ovf/0r3bt3T/v27WttV15enubNm2fVVVddYC2NGzeu89waa6yRLl26ZOedd86f/vSnHHvssUmSP/7xj7nzzjszfPjw7LLLLqX+HTt2TPfu3bPOOuvk2muvzaGHHpp11113geNdd911admyZYYMGVIKOS+55JL06dMnTzzxRHbdddckycUXX5yDDjoom222WQ455JA6rzN9+vTccsstOeqoo0qhUKdOnfLqq6/mqquuyplnnpmVVlqpzvGYP94GG2yQ73//+wusMUnuvffezJgxI3feeWf233//hfb7KsrLy2sd61VXXTVdunTJlClTcvnll+fkk0/OGmusUXp+lVVWqRVsrrbaarnwwgvz8ssv57rrrqsTLn6xPwAAXx/XXAQA6k379u3TvXv33HHHHbXa586dm3vuuafWKa/zzZo1K3PmzKnT3rRp0/zpT3/KoYceulRrXH311dO+ffv85z//KbWNGDEiO++8c61g8fP69++fJ554YqHBYpKMHTs2m266aa3VkxtttFE6duyYp556qtR20UUX5YgjjqizsnO+Vq1a5YknnsiAAQNqta+22mqpqalZ6Eq30aNHZ9SoUTnttNMW+tpJsssuu2TEiBGLfSrukthoo42SJB988MGX9i0vL88GG2xQ6/fyTXXqqafm1FNPre8yAIBvKOEiAFCvvve97+Whhx6qdU27J598Mp988kn23HPPOv133nnnPPDAAzn++OPz97//fYFB49I0ZcqUTJ06tXRK9MSJE/Pee+8tNFhM5l2vcf5pzQvTuHHjNGrUqE57+/bta13Hb1EB5fyx2rdvXyukTOadGrzGGmtk9dVXX+B2Q4cOzc4775zNNttska+/zjrrLLDOr8Pbb7+dJFlzzTUXq/9bb71V+r0AAFA/hIsAQL3aZ599Mnfu3PzlL38ptY0aNSo77rhj2rVrV6f/2Wefnb333jv33XdfDjzwwGy99dbp379/rr/++qV+fbj3338/p5xySlq0aJEf//jHSZIPP/wwyeIHYAvzrW99K//+978zd+7cUtvs2bPz9ttv57PPPlui177xxhvz1FNP5cQTT1zg86+88kqefPLJHHHEEUs0ztJSWVmZp556Ktddd1322GOPLz2206ZNy+9+97u89tprOeigg5ZRlQAALIhrLgIA9apdu3bZaaedcscdd+QnP/lJKioq8uijj9a5Cch8bdq0ye9///t88MEHefzxx/P3v/89zz//fJ599tlcccUVueqqq9K9e/evXMeYMWNqbVdVVZXZs2dnq622yvXXX19aITd/RWJ1dXWt7UePHl3nmoi9e/fOb37zmwWOd+CBB+b+++/Peeedl+OOOy6VlZU599xzU15ensaNi39Fu/7663PBBRfkqKOOSu/evRfY54YbbkjXrl2z5ZZbFh5nSUyePLnWsZ49e3YaN26cPn36LPD03m233bbW4xkzZqRz58658MILF7i69Yv95zv11FML/W0sjz6/H/NX7z744IOlts+H9QAAXyfhIgBQ777//e/n2GOPzZtvvpnnnnsuTZo0WeD1Fj9vrbXWSr9+/dKvX79UV1fnr3/9a0477bScddZZueuuu75yDRtuuGEuvfTS0uNHHnkkF110UU488cR85zvfqTVukrz33nu1tt9oo41y5513lh6feOKJizxle6uttsqFF16Ys88+OzfffHOaN2+eQw45JNtuu+2XnlK9IDU1Nbnoooty3XXX5YQTTsjhhx++wH6VlZV55JFH0r9//688xtKy8sor59Zbby09nn8znQXd4TlJbrvttjRp0iTJvNPSf/azn+VHP/pR9ttvvy/t/3nt27fPxIkTl3wHlgOf/1u7+OKLk6TWStXVVlttWZcEAHxDCRcBgHrXs2fPtGnTJvfdd1+efvrp9OrVKy1atFhg308++SQrrbRSrbby8vLstdde+cc//pEbb7wxNTU1i7xJyYI0bdq01vUN+/fvn/vvvz+nn356Ro0aVQq+VllllWywwQb561//WusmKl/cvnnz5l865n777Zd99tknkydPTocOHdK0adPsvffe6dOnz1eqPZkXMI0cOTK//e1vF3n35+effz6ffPJJ6W7U9aFRo0Zfei3Jz1tnnXVKd39ed911c/DBB+eyyy7LHnvskc6dOy+y/xetKOHi549fq1at6rQBACwrrrkIANS7Zs2aZc8998x9992Xf/3rXws9nfevf/1rtt566zz77LMLfP7999/Pqquu+pWDxQUpLy/PWWedlfHjx+fKK6+s9dwRRxyRf/7zn/nzn/+8wG2nT59eujbjwrz22mv585//nKZNm2bNNddM06ZNM3bs2IwfPz69evX6SrWOGjUq1113XS6++OJFBotJ8txzz6VFixbZZJNNvtIYy5NBgwalXbt2OeOMM1JTU1Pf5QAAfKMJFwGA5UKfPn3y1ltvpUOHDtl+++0X2GfXXXdN9+7d84tf/CLXX399XnnllXzwwQf55z//mV/96ld55JFHMmjQoKVWU9euXdOvX78MHz48b7zxRqm9d+/eOeSQQ3L66afnN7/5Tf71r39l4sSJ+fe//53rr78+++67b6ZNm5Yf/vCHpW2GDBmSAw44oPR44sSJ+eUvf5lLL7007733Xp577rkcd9xx+a//+q906dIlybzrPk6aNCmTJk3KtGnTksxbuTm/LZl3/cELLrgg++yzT7bccsvSc/P/N2vWrFr79NZbb2XttddeaAC71157ZcSIEaXHFRUVpdeafx3Khb32stKqVav88pe/zPPPP5/bbrutXmoAAGAep0UDAF/ZaaedVjrt980338wpp5ySJPnd736XlVdeOUkyYcKEr3Tq7dZbb52OHTumZ8+eadSo0QL7NG3aNCNGjMgf/vCH3H333fmf//mfTJ8+PSuttFI222yzXHPNNdlpp52WaN++6Nhjj82DDz6Y0047LTfffHPpeoi//OUvs/POO+emm27KwIED88knn6R169b59re/nZ/+9Kfp169f2rRpU3qdSZMm5Z133ik93mWXXXLOOefk2muvzTXXXJMOHTrkRz/6UX7+85+X+kycODHf/e53a9VzwgknlH5+9dVX8/LLL6eioiL33ntv7r333jr1n3/++bVCzmnTpqV169YL3d/x48dn8uTJpceDBw/O888/X3r8n//8J4888sgCX/vzjjzyyNLPS/su3kmy5557Zuedd85FF12UXXfd9StdY/CGG24o3fxk8uTJOemkk5Ik9957b15++eUkyWeffVbat2effba0P1VVVaVrcL722mu19nN+DZMnT67V/vm/54UdlyWZUxdccMFC9/Wrvu7Cjg0AwMKU1TiXBAAAAAAowGnRAAAAAEAhwkUAAAAAoBDhIgAAAABQiHARAAAAAChEuAgAAAAAFCJcBAAAAAAKES4CAAAAAIUIFwEAAACAQoSLAAAAAEAhwkUAAAAAoBDhIgAAAABQiHARAAAAAChEuAgAAAAAFCJcBAAAAAAKES4CAAAAAIUIFwEAAACAQoSLAAAAAEAhwkUAAAAAoBDhIgAAAABQiHARAAAAAChEuAgAAAAAFCJcBAAAAAAKES4CAAAAAIUIFwEAAACAQoSLAAAAAEAhwkUAgAbq4Ycfzt57752ZM2cuVv877rgjO+yww9dcFcvK3//+9+yyyy6ZMmVKfZcCAHyDNa7vAgAAGoIHHnggDz74YOnxsccemw8//DA333xzqe3ggw9OmzZtcvnll5favve976V79+45++yzS23bb7999t9//xx33HGlto033jhHHHFEzj777FJYtPrqq+fUU09dYD2TJk3KaaedlquvvjotWrRIkjz++OO5+uqr89prr2XGjBlZc801s//+++fwww9PWVnZ0jkQX3D77benZ8+ead++/Zf2ra6uzqWXXpp77703n3zySTbbbLOcddZZWWeddRbYf9y4cbngggvy8ssvp2XLltlzzz1z0kknpWnTpl861rBhw/Lkk0/mT3/601fep6/bhAkT8utf/zovvfRSWrZsmX322ScnnHBCyssX/O/+N998c66//vp89NFH6dSpUwYPHpzdd989W2+9dXr16pUzzjij1t8cAMCyJFwEAFgM7777bi655JIkyf/+7/9m6tSpef/99/PLX/4yq666at5///289NJLWWWVVXLIIYdk8803T5IMHz48G264YXbffffsu+++pbbk/wLFz7etvvrqOeOMM2q1Lci1116bbt26ZbPNNkuS/Otf/8rgwYNz7rnnZvfdd0/Tpk3zz3/+M7/4xS9SU1OTI488cqkfk6qqqlxwwQXp3r172rdvn9GjR6dbt24LDTJvuumm3HPPPbn66quz+uqr55JLLsnRRx+du+66q842n332WQ477LD86Ec/yvDhw/Pee+/l8MMPT7t27TJw4MClvi9Ly+TJkzNjxoyFBqZJMnjw4HTt2jUPP/xwJk+enCOPPDKrrLJKDj300Dp9H3zwwQwZMiRXXXVVNttss9x555059thjc//992edddbJEUccke9+97sZO3Zsunbt+nXuGgDAAjktGgCggZk7d25uu+22/Nd//Vep7fnnn8/aa6+d3r17p0WLFmnUqFG22mqrDB06NFtvvXWt7R966KF897vfTbdu3XLyySensrIyybyVhZdffnl69eqVzTbbLD/4wQ/y7LPPlrbr2bNn/ud//iff/e53c+aZZ2abbbbJp59+mj59+uSyyy7LFVdckV69emX48OH5+OOP69R96623pn///unSpUtat26d4447Lm+++WZeeumlOn0nT56cnXbaKYMHD07Tpk3TpUuX7LnnnnnhhReWyjGcNm1aTj755Oy4447p3r17jjjiiLz//vtJkvfffz8bbrhhnn766ey3337ZfPPN07dv39LzSXLFFVdk6623znbbbZfrr78+hx56aIYNG5aKior07ds3P/vZz/LXv/41c+fOrTXumDFjMm7cuJx44olp06ZNOnfunP79++fWW29dYJ2zZs3K8ccfny233DJNmjTJ/vvvn1atWuVf//pXkmS11VbLbrvtlltuuWWpHBcAgK9KuAgA0MCMGTMmn332WbbZZptS27e+9a2MHz8+t912W+bMmVNq33LLLbPFFluUHn/22Wd58cUXc8899+TWW2/Nfffdl8ceeyzJvJWFt912Wy677LK88MIL6d27dwYOHJjJkyeXtv/LX/6S6667LmeddVbuuuuuJMldd92VQYMG5corr8ywYcPy/vvvZ999980xxxyTZ555JjU1NZk1a1beeOONbLLJJqXXat26ddZdd92MGTOmzj526tQp559/fho3/r8TbSZOnJjVV199KRzB5PTTT8+kSZNy991358knn0zz5s1z7LHH1uozcuTIXHXVVfnb3/6WGTNm5JprrkkyL5y98sor8z//8z955JFH8uabb2bs2LFJki5duuSxxx7Lj370o9x4443Zddddc8kll5SCybFjx6Zjx45p27ZtaZyuXbtm/PjxmT59ep06+/TpkwMOOKD0+JNPPslnn31W6zj06NEjzz333FI5LgAAX5VwEQCggXnjjTey+uqrZ+WVVy617b777hkwYEB+/etfp0ePHjn00EMzfPjwTJgwoda2s2fPzuDBg9OyZctssskm+fa3v53x48cnmXf9xAMOOCAbbrhhmjZtmgEDBqRFixb529/+Vtp+p512yrrrrrvQU5833njj/OY3v8mjjz6aHXbYIRdffHH69euXadOmpaamplaoliRt27bN1KlTv3SfH3nkkTz22GMZMGDAYh6lhauoqMhDDz2UY489Nu3bt0/r1q1zzDHHZMyYMXnvvfdK/fr161c6zjvuuGPefPPNJPOubbnjjjtmq622SsuWLXPyySdn1qxZpe2aNm2affbZJyNHjswf/vCHzJ49O/vvv39uvvnmVFRUZKWVVqpzDJJ86XGoqanJ6aefnu985zu1guX1118/7777bq0aAACWFeEiAEADM3Xq1DohXVlZWU466aQ8/fTTOffcc9O5c+fccsst2WOPPXLnnXeW+rVr1y6tWrUqPW7evHlppeP777+fLl261HrdTp061QooO3bsuFg1VldXZ86cOZkzZ06aNGlSaq+pqVns/Zzvr3/9a0488cT89re/zfrrr/+Vt/+iDz74IDU1NbX2tVOnTklSa1/XXnvt0s8tWrTI7Nmzk8y7mc7nj8P805sXpLKyMnPmzEl1dXUaNWqUpNgxqKyszIknnpg33ngjl156aa3n2rVrl+TLw0kAgK+DG7oAADRAC1s52LZt2+yzzz7ZZ599UlNTk1/96le58MILs99++y1yuyS1Tqde2FjzA7KFGT16dG655ZY88sgj2WmnnXLWWWdlq622yuzZs1NeXp6Kiopa/SsqKtKhQ4eFvt6tt96aiy++OMOGDcuOO+64yLEX18L2M6m9rws7VtXV1bVO105S607Pc+bMyf33359bbrkl//nPf/LjH/84d999d1ZfffX86U9/WuAxKCsrW+gdt2fNmpWBAwdm5syZuemmm0ph4hfrLBJaAgAsKSsXAQAamHbt2tUJqK655ppapy8n80KnHXfcMbNmzVqs4KlTp0556623So/nzp2bd955Z5F3Pv68ww8/PKeccko22GCDPPjgg7n44ouz1VZbJUmaNWuW9ddfv3RtwmTe9QPffffd0h2vv+iBBx7IJZdckpEjRy61YDFJaX8+v6/zf56/gnFROnTokA8++KD0ePr06aVTy994443suuuuuf/++3PkkUfmkUceydFHH126RuKmm26aiRMnZsqUKaXtx4wZk/XWW6/WitL5ampqctxxx6Vx48a5/vrr6wSLSUqvtbBwEgDg6yRcBABoYNZbb7189NFHmTZtWqltxowZOe200/L4449n1qxZqa6uzquvvprhw4enZ8+ei1yxOF+fPn3yxz/+MW+++WbmzJmTK6+8MlVVVenZs+cC+zdv3jxJ8vbbb2f69Ok5/vjjc//996d///61rgc5X79+/TJy5Mi8+eabmT59ei6++OJsvPHG6datW5JkyJAhueCCC5Ikn376ac4666xcdNFF2XjjjRc4/l577VXo7tEdOnTIjjvumEsvvTQVFRWZNm1afv/736dHjx5Zc801v3T7bbfdNk888URGjx6dWbNm5be//W3pWLRv3z533HFHrrzyyuy66661VjQmySabbJJu3bplyJAhmT59et58882MGDEi/fr1W+B+3XPPPaVToZs1a7bAel5//fV06tSpVAMAwLLktGgAgMVQWVmZ4447LkkyefLkHH/88UmSM888M82aNcvMmTPTu3fvJMmll15aCtfmB2N/+MMf8vDDDydJaRXbvffem1deeSVJStclfOaZZ0ptn376aY444og6tXTr1i0tW7bM888/n169eiVJBg8enLZt2+aSSy7Je++9lzlz5mSNNdbI3nvvnYEDBy7WPg4YMCBTp07N4Ycfnk8++SQbb7xxRo4cWecGJPOtssoq2XPPPfOLX/wiffv2zVNPPZV33323Tr+OHTvmoYceSt++fTNp0qQcdNBB+eyzz9KjR49cdtllpX6TJk0qXdfwkUceydSpUxdY+/y7S48fP36RNzEZPXp0Kbic74c//GF+/etf58ILL8yvf/3r7L333ikvL892222X888//8sPUpLvf//7efnll3PwwQenbdu2OeaYY/LKK6+krKws48ePz0EHHbTA7QYOHJhBgwZl6NCh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WcrLnfkNAAAAAF9FdXV1Zs+enbZt26Zx44Wf/LxChosAAAAAwNfPsj4AAAAAoBDhIgAAAABQiHARAAAAAChEuAgAAAAAFCJcBAAAAAAKES4CAAAAAIUIFwEAAACAQoSLAAAAAEAhwkUAAAAAoBDhIgAAAABQiHARAAAAAChEuAgAAAAAFCJcBAAAAAAKES4CAAAAAIUIFwEAAACAQoSLAAAAAEAhwkUAAAAAoBDhIgAAAABQiHARAAAAAChEuAgAAAAAFCJcBAAAAAAKES4CAAAAAIUIFwEAAACAQoSLAAAAAEAhwkUAAAAAoBDhIgAAAABQiHARAAAAAChEuAgAAAAAFCJcBAAAAAAKES4CAAAAAIUIFwEAAACAQoSLAAAAAEAhwkUAAAAAoBDhIgAAAABQiHARAAAAAChEuAgAAAAAFCJcBAAAAAAKES4CAAAAAIUIFwEAAACAQoSLAAAAAEAhwkUAAAAAoBDhIgAAAABQiHARAAAAAChEuAgAAAAAFCJcBAAAAAAKES4CAAAAAIUIFwEAAACAQoSLAAAAAEAhwkUAAAAAoBDhIgAAAABQiHARAAAAAChEuAgAAAAAFCJcBAAAAAAKES4CAAAAAIUIFwEAAACAQoSLAAAAAEAhwkUAAAAAoBDhIgAAAABQiHARAAAAAChEuAgAwGI588wz87Of/SzV1dX1Xcpyb/To0enRo0def/31+i4FAOBrVVZTU1NT30UAAHzTDRs2LK+99lrKysqSJOuvv34GDx6cAw88MO3bt0+STJgwIZdeemkmTJiQoUOHpkOHDqXthw4dmrPOOitTpkxJksycOTN77713fvjDH2bvvffO+uuvnyR54403ct999+WOO+7Ifffdl5YtWyZJOnTokDPPPHOh9d1555256KKLcu+99+a1115bpuPPnDkzF154YZ544olUVFRkvfXWy6BBg7LzzjsvtN7p06fnt7/9bR588MHMnj07G220UX75y19ms802W+g2I0eOzJ/+9KdMmDAha665Zvbff/8ceuihC+3/eX//+99z8MEHZ+DAgRk8eHCS5Lrrrsstt9ySu+66Ky1atFis1wEAaGga13cBAADMc8kll6Rx43lfz4YNG5Yk2XLLLXPcccclSe64445S36OPPjrbb799rb5t27bNWWedlSR5//338/zzzydJ9thjj9JrzO+bJGeccUbWXXfdOu1fNGPGjFx88cU5/PDD065du2U+/m9+85uMHj06V199ddZee+2MGjUqAwcOzF133ZUuXboscJvjjz8+lZWVufPOO9OmTZtcffXVueSSS3LttdemvLzuyTt33nlnLrnkkgwbNizbbLNNRo8enSOPPDKtW7fO/vvvv9DakuSzzz7LqaeemlatWtVqP/DAA/OHP/whN9xwQ4466qhFvgYAQEPltGgAABbprrvuyqeffpqf/OQny3zsadOm5Z577snRRx+dLl26pFmzZunbt2/WW2+9/PGPf1zgNqNHj85TTz2Vc889N2uuuWZat26d4447LiNGjCgFi1dccUV69uxZ2mbkyJHp06dPdtxxxzRt2jRbbbVVfvSjH2XkyJFfWuP555+fjTfeOBtvvHGt9qZNm+anP/1pRowYkaqqqiU4CgAAyy/hIgAAi/TEE09k6623rpdTe8eOHZvKyspsvvnmtdo322yz/Otf/1rgNs8++2zWXHPN/O1vf8vuu++ebbbZJocffnjefvvtUp+BAwfm0UcfTZLMmTMn48aNW+AYr7/+ej777LOF1vf444/n4YcfLq3Y/KIdd9wxFRUVGTNmzJftKgBAgyRcBABgkcaNG5dNNtmkXsaefw3Htm3b1mpv165d6bkvmjhxYj7++OOMHTs2d9xxR+6+++7MnTs3RxxxRObMmVOnf0VFRaqqqhY4Rk1NzULHqaioyGmnnZZf/epXWWWVVRbYZ4MNNkijRo3yyiuvfOm+AgA0RMJFAAAWacqUKaVrLTYENTU1mTNnTk477bSstNJKWWONNfLLX/4y77zzTl544YWlNs6vf/3rbLHFFtlnn30W2qe8vDxt27ZdaEAJANDQuaELAADLrfl3pK6oqKh1w5SpU6cudLXgaqutliZNmpTuRJ0knTp1SpJ89NFHdfqvvPLKady4cSoqKmq1T506NWVlZbXuij3fX/7ylzz33HP5y1/+8pX3CQBgRWLlIgAAi9S+fftMnTq1XsbedNNN07Rp07z00ku12v/xj3+ke/fuC9xmww03zOzZs/Paa6+V2t55550kydprr12nf9OmTdO1a9c613B88cUXs9FGG9UKKee75ZZb8tlnn2XvvfdOjx490qNHj/zjH//INddckx/84AelftXV1Zk2bVqDWvkJAPBVCBcBAFikDTfcsN6uGdimTZv86Ec/ymWXXZa33norM2fOzLXXXpt33303P/3pT5MkH374Yfbaa6/SKc+77LJL1ltvvfzmN7/JRx99lClTpuSCCy7IxhtvnC222GKB4/Tv3z933XVXnn766cyZMydPP/10Ro0alUMPPbTU55BDDsmIESOSJJdeemn++te/5q677ir9b9NNN03fvn0zfPjw0javvfZaqqqq6txJGgBgReG0aACA5cRxxx2XsrKyJMn666+fZN7quWOOOSZJMmHChGyzzTZJkssvvzy33HJLre2nTZtW6jtz5szsvffeSZK//vWvGT9+fJLkjTfeyODBg5MkZ599dmlV3oJO/Z1vl112yYUXXphZs2alefPmy3z8X/7yl/ntb3+bAw88MJ9++mk23njjXHvttVl33XWTJJWVlRk/fnxmzJiRJGnSpEmuueaanHPOOdlrr71SU1OTnXbaKRdeeGHKy+f92/oVV1yR22+/vXTH6H322SeffPJJzjrrrEycODFrrrlmTjnllPTp06dUx3vvvZfJkycnmbea84uaNm2a1q1bZ9VVVy21PfXUU1l55ZWz2WabLXT/AAAasrKampqa+i4CAIDl14wZM9KrV68ceeSROfjgg+u7nAajsrIye+65Z/bff//8/Oc/r+9yAAC+Fk6LBgBgkVq2bJnjjz8+w4cPr3PTExbupptuSnl5eQ455JD6LgUA4Gtj5SIAAIvlV7/6VSZOnJjhw4eXTt9mwUaPHp3DDz88f/jDH7LBBhvUdzkAAF8b4SIAAAAAUEi9nxb95JNPZvvtt89xxx23yH7V1dW55JJL8t3vfjdbb711fvazn+W9995bRlUCAAAAAF9Ur+Hi1VdfnXPOOad0p79Fuemmm3LPPfdk+PDheeyxx9K5c+ccffTRsfASAAAAAOpH4/ocvFmzZrn99ttz7rnnZvbs2Yvse+utt6Z///7p0qVLkuS4445Ljx498tJLL2XzzTev1Xfu3LmZNm1amjVrlvLyel+cCQAAAAANSnV1dWbPnp22bdumceOFR4j1Gi4efPDBi9Vv1qxZeeONN7LJJpuU2lq3bp111103Y8aMqRMuTps2LW+//fZSrBQAAAAAvnk6d+6cDh06LPT5eg0XF9e0adNSU1OTtm3b1mpv27Ztpk6dWqd/s2bNkszb+ebNmydJampqMn369LRu3drdDaEBMoehYTOHoWEzh6HhM4+hYauPOTxr1qy8/fbbpZxtYRpEuDjf4l5fcf6p0C1atEjLli1L286dOzetWrXyRgoNkDkMDZs5DA2bOQwNn3kMDVt9zOH543zZJQcbxAUJV1555ZSXl6eioqJWe0VFxSKXZQIAAAAAX58GES42a9Ys66+/fsaOHVtq++STT/Luu+9ms802q8fKAAAAAOCba7kNFz/88MPstddeee+995Ik/fr1y8iRI/Pmm29m+vTpufjii7PxxhunW7du9VwpAAAAAHwz1es1F+cHg3Pnzk2SPPzww0mSMWPGpLKyMuPHj8+cOXOSJH379s2kSZNy0EEH5bPPPkuPHj1y2WWX1U/hAAAAAED9hotjxoxZ6HNrr712Xn311dLjsrKyHHPMMTnmmGOWRWkAAAAAwJdYbk+LBgAAAACWb8JFAAAAAKAQ4SIAAAAAUIhwEQAAAAAoRLgIAAAAABQiXAQAAAAAChEuAgAAAACFCBcBAAAAgEKEiwAAAABAIcJFAAAAAKAQ4SIAAAAAUEjj+i6gIZkzZ04efvjhPPbYY5k0aVKqqqrquyQagKZNm2a99dbLXnvtle7du9d3OQAAAABLjXBxMc2ZMycnnHBCnnzyyay//vpZa621Ul5u4Sdfbs6cOXnkkUfypz/9Kaeeemp+8pOf1HdJAAAAAEuFcHEx3XPPPXnqqadyxhln5Dvf+U59l0MDU1NTk2uvvTa//e1v893vfjerrLJKfZcEAAAAsMQsvVtMjz76aDbddFPBIoWUlZXlJz/5SWpqavL444/XdzkAAAAAS4VwcTFNnDgxnTp1qu8yaMDatGmTDh065D//+U99lwIAAACwVAgXF1N1dbVrLLLEGjVq5EZAAAAAwArDNReXwJ///Oe89dZbSZK11147/fr1y69//eu0bNky1dXV6d27d6ZPn146DbampiYnn3xyrrvuukyePDlJ0rVr1+yzzz6LHKempiY333xznnzyyVRXV6eysjJdunTJUUcdlQ4dOuShhx7K/fffn9/97ndLvE8PPPBAevXqlUaNGi2y34wZM3LppZfmjTfeSHl5eXbbbbcccMABC+x733335d57701lZWVWWmmlDBw4MF26dFnk6y/NfVpS7777boYNG5apU6emadOmOeigg7LddtvV6VdZWZlrrrkm//rXvzJ37tx8+9vfzjHHHJM2bdrUQ9UAAAAAXz/h4hJo2rRpTjrppCTzbviSJFtssUV69+6dDz/8MO+8806mTZuWQYMGpUWLFqU+q666agYMGFBru0W599578/zzz+eiiy5K69atM3fu3Fx55ZUZMmRIzjvvvKW2P1VVVbnmmmvSs2fPTJs2LXfccUf23nvvdOzYsU7fG264IU2bNs3VV1+dWbNm5YQTTsi3vvWtOqHbyy+/nD/+8Y8ZOnRo2rdvn1GjRuWSSy7JZZddttTqXlL/+Mc/8vbbb6dXr14LDAIvuOCC9OnTJ3vuuWfefffdnHTSSdlwww3Tvn37Wv1uu+22TJgwIZdddlnKy8tz/vnn549//GOOPPLIZbUrAAAAAMuUcHE58cwzz+TJJ5/MKaecUue59957L506dUrr1q2TJI0bN85hhx2WysrKWv1GjhyZZ555JnPmzMmgQYOyxRZbpKamJrfeemsee+yxJMlqq62WgQMHZs0118xNN92Ujz76KBMnTsxGG22Uf//735k5c2YGDRqU448/PmussUbOPffctG/fPvvss0969OhRWtH4+OOP5+yzz055eXlatmyZnj175m9/+1udcLFdu3Y59dRTS0Hclltumeuvvz41NTUpKysrdKw+++yzXHXVVXnllVdSXl6erl275ogjjkjz5s1z6qmnZptttskLL7yQCRMmpGPHjjnjjDPSokWLvPTSS/n973+fxo0bZ5tttslbb72Vnj17Zuutt86YMWMyePDgbLbZZtlnn32y0UYbJUnefvvtTJo0Kb169UqSdOrUKRtuuGGeeeaZfO9736tV1+abb56dd945TZo0SZJ07949Tz/9dKF9BAAAAGgIXERwObH99tsvMFhMkm222SZ/+9vfMnTo0Dz//PP57LPP0rx581qr7N5+++107949V155Zb73ve/lxhtvTDIvtHzkkUdy0UUX5aqrrspGG22U3//+96Xt/vd//zcnnnhiBgwYUFqFedlll2WjjTbK9773vVxxxRXZf//987e//S2HHXZYbrnllnzyySf59NNPs8Yaa5ReZ6211sqECRPq1N6xY8dsuummpcfPPfdcNtxww8LBYjIvRJ01a1auvPLKXH755fnoo49y++23l55/+umnc8YZZ+Taa6/NlClT8vTTT6eqqipDhgzJIYcckquvvjqdOnXKK6+8kiRZeeWVS+2bb755rr766hxzzDF5+umnM2HChKy++uq1rre55pprLnBfN9lkk6y99tq19nXjjTcuvJ8AAAAAyzvhYgOw1VZb5bzzzsuMGTPy+9//Pn379s3pp59eut5jMm9FYrdu3ZIk3/72t/Pxxx8nmRce7rbbbllppZWSJPvuu29efvnlzJo1K0nSpUuXrLbaaosc/zvf+U6OP/749OzZM7fffntmz56dZN5p4fM1bdq09JoL87//+78ZNWpUBg4c+BWPQN3X6d27dxo1apTGjRtnzz33zIsvvlh6ftttt02LFi3SuHHjdOrUKZMmTcqECRNSUVGRnXbaKUnSq1evtGjRotbrNmnSJD179sx///d/Z5VVVslDDz2U2bNnl1YiztesWbMv3dfrr78+U6dOzY9//OMl2lcAAACA5ZnTohuITTfdtLQC8O23386tt96aM888M9dff32SpGXLlqW+5eXlpTsST506NRtssEHpufmrHadNm5YkpdBxYSZMmJC//OUveeqpp7L11lvnwgsvTPPmzZMks2fPTrNmzZIkc+bMKbUvyIMPPpibbropv/nNb9K5c+evsOd1VVRUpG3btqXHbdq0SUVFRelxq1atSj83atQo1dXVmT59elq1alU6rbu8vDwdOnSo9bqjR4/OvffemzfeeCO777579txzz4wbN64Ups43e/bsOsHkfFVVVbn88sszfvz4nHfeeQvtBwAAALAiEC42AC+++GI22GCDUjDYuXPnDBw4MH379q0Vqi1Iu3bt8umnn5Yez/955ZVXXuR2n332Wc4///xMmTIle++9d6688spaAWbbtm0zYcKEUjj5/vvvp1OnTgt8rYceeii33357Lrzwwqy55ppftrtfauWVV84nn3xSevzpp5+mXbt2i9ymZcuWmTVrVqqrq1NeXp6amppMmTIlSfL666/nkksuSbt27bLvvvvmlFNOKYWQ66yzTj788MNUVVWV2iZMmJAddthhgeMMHTo006ZNy/nnn7/IsBUAAABgReC06AbgrrvuyvDhwzNz5swkSXV1dR555JGsvfbadVbffVGPHj3y6KOPZvr06UmSu+++O1tssUVpxeHnzQ/P5vft27dvrrjiivTu3btWsJgkPXv2zKhRo1JdXZ1p06blwQcfTM+ePeu85sSJEzNixIicffbZSyVYnL9Pf/nLX1JdXZ3Kysrcf//92XbbbRe5TceOHdO8efM899xzSZJHHnmkdGpz8+bNc9ppp+Xcc8/N9ttvXzoOybwbuHTs2DH33ntvkmTcuHF5/fXXs/3229cZ47HHHss777yT0047TbAIAAAAfCNYubgEPvzww1x00UVJ/u9U3EcffbR0Ku0ee+yRZN5qtvLy8kyZMiW9e/fO66+/XtpurbXWSrLou0Wfcsopuf7663PMMcekrKwsc+fOzYYbbpizzjrrS2vcYYcdMmHChJx44ompqanJWmutlV/84hcL7Nu+fft069YtRx55ZI488shce+21dfo0b948I0aMyIEHHphhw4bliCOOSHl5efbZZ59stdVWSZJ77rknH374YQ477LDcf//9mT17ds4888xar/OrX/0qzZo1y2mnnZbLLrusznUNk2T8+PE58sgja7Wde+65OeSQQ3LllVfm5z//eZJ5d2Xeb7/9FnkcmjRpksGDB+eaa67JjTfemO233z6dO3dOWVlZ3nrrrVx55ZV1ttliiy1y0kkn5ZRTTsmwYcNy7733plmzZjn55JNLp2UPGTIkW2+9dXbeeefcfffd+eijjzJo0KDSa7Ru3TpDhgxZZG0AAAAADVVZTU1NTX0XsbTNmDEjr7zySjbeeOPSiruamppMmzYtbdu2LXSn4v322y/dunXLIYccsrTL/UY755xzctpppy3R3aO/ipqamtJYhx9+eA477LD06NFjmYydJIMGDco+++yTY445ZpmNuaJY0jkM1C9zGBo2cxgaPvMYGrb6mMMLytcWxGnR1Ju5c+dmp512WmaT4qSTTsr999+fZN7pzZMnT8566623TMYGAAAAWBE5LZp607hx4+yyyy7LbLwjjzwyw4YNy6hRo9KoUaMce+yxX3rNSgAAAAAWTrjIN8Z6662XSy+9tL7LAAAAAFhhCBeXwJ///Oe89dZbSZK11147/fr1y69//eu0bNky1dXV6d27d6ZPn57HH388ybzz408++eRcd911mTx5cpKka9eu2WeffRY5Tk1NTW6++eY8+eSTpTskd+nSJUcddVQ6dOiQhx56KPfff39+97vfLfE+PfDAA+nVq1etOybP9/TTT+fGG29MZWVl2rdvn8GDB2edddap06+qqirXXHNNnnnmmTRq1Cg77LBDBgwY8KWnPx966KE5+uijSzeGWZbefffdDBs2LFOnTk3Tpk1z0EEHZbvttlvkNsOHD8+zzz6bESNGLKMqAQAAAJYvwsUl0LRp05x00klJ5t0hOZl3h+HevXvnww8/zDvvvJNp06Zl0KBBadGiRanPqquumgEDBtTablHuvffePP/887nooovSunXrzJ07N1deeWWGDBmS8847b6ntz/xQsGfPnnXCxY8//jiXXnppLrrooqy77rp58MEH89vf/jbDhg2r8zp//vOf88477+Saa67J3Llzc9555+Xtt9/Ot771raVW69J2wQUXpE+fPtlzzz3z7rvv5qSTTsqGG26Y9u3bL7D/uHHj8vzzzy/jKgEAAACWL8LF5cQzzzyTJ598Mqecckqd595777106tQprVu3TjLvWoWHHXZYKisra/UbOXJknnnmmcyZMyeDBg3KFltskZqamtx666157LHHkiSrrbZaBg4cmDXXXDM33XRTPvroo0ycODEbbbRR/v3vf2fmzJkZNGhQTjjhhEyePLlU0zPPPJNNNtkk6667bpJk9913z/Dhw/Puu++mU6dOter461//msGDB6dJkyZp0qRJzj777CU+Pv/7v/+bP/zhD6msrEyzZs1y6KGHpnv37hk9enSuvPLK7Lbbbnnssccyffr0DBgwILvuumsqKytz6aWX5p///GdWW2217Lbbbhk1alRGjBiRjz/+OKeddlouu+yyTJgwIZMmTUqvXr2SJJ06dcqGG26YZ555Jt/73vfq1FJZWZlhw4bl0EMPzTXXXLPE+wYAAADQUAkXlxPbb799tt9++wU+t8022+Q3v/lNGjdunG233TZdu3ZNq1at0rx581Kft99+O4ceemgOPvjg3HHHHbnxxhuzxRZb5JlnnskjjzySIUOGZKWVVspNN92U3//+97nwwguTzAvthg4dmtVWWy0ffvhhBgwYkMsuuyxNmzYt1ZUkEyZMyJprrlkar1GjRll99dXz/vvv1woXZ86cmYkTJ+a9997Lddddl9mzZ2f33XfPj3/848LH5uOPP85vf/vbXHjhhVlvvfUyevTonHPOObnuuuuSJB988EFWWWWVXHHFFXnssccycuTI7LrrrvnrX/+at99+O9ddd13mzp2b//7v/y695iqrrJKrrrqqtG+rr756ysv/7+bpa665ZiZMmLDAem655ZZ0797dnaYBAACAb7zyL+9Cfdtqq61y3nnnZcaMGfn973+fvn375vTTTy9d7zGZtyKxW7duSZJvf/vb+fjjj5PMCw932223rLTSSkmSfffdNy+//HJmzZqVJOnSpUtWW221L61h9uzZadKkSa22Zs2alV5nvs8++yzJvNWWv/vd73LmmWfmzjvvzLPPPltw75N//vOfWX/99Uth3mabbZb27dvnlVdeSZKUl5dnt912SzJv3ydNmpQkGTNmTLbffvs0a9YsrVq1yu67775E+5Yk48ePz1NPPZUDDzyw8P4AAAAArCiEiw3EpptumlNPPTV//OMfM2zYsLRp0yZnnnlmqqqqkiQtW7Ys9S0vLy+1T506tRQsJkmbNm2SJNOmTUuSWs8tSvPmzTN79uxabbNnz06LFi1qtc0/dXuPPfZIo0aNsuaaa2bHHXfMP/7xj6+yu7VMnTo1bdu2rdW20korpaKiIklq1VBeXp7q6uokyfTp02vt36qrrrrA12/WrNli7VtVVVWGDh2an//857VWjQIAAAB8UwkXG4AXX3wxn376aelx586dM3DgwEyZMqUUsC1Mu3btam07/+eVV175K9Ww9tpr54MPPig9njt3bj788MM611ts3rx5Vl555cycObPUVl5evsC7Ty+uL+5DknzyySdp167dIrdr2bJlZsyYUXo8/w7dX7TOOuvkww8/LAWyybxTpb94J+z33nsvH3zwQS699NIceuihOemkk/Lxxx/n0EMPrVMfAAAAwDeBcLEBuOuuuzJ8+PBSYFddXZ1HHnkka6+9djp06LDIbXv06JFHH30006dPT5Lcfffd2WKLLdKsWbM6fecHgPP7ft7222+fV199Na+//nrpdTp16pSOHTvW6durV6+MGjUqVVVVmTZtWp555plstdVWX22nP6d79+557bXXSqeB//Of/8y0adOyySabLHK7jTfeOM8++2wqKyszY8aM0k1tvmj+ftx7771J5t0J+vXXX69zDczOnTvn1ltvzYgRIzJixIhcdNFFWWWVVTJixIjSilAAAACAbxI3dFkCH374YS666KIkSatWrZIkjz76aMaNG5fZs2dnjz32SJIMHTo05eXlmTJlSnr37p3XX3+9tN1aa62VZNF3iz7llFNy/fXX55hjjklZWVnmzp2bDTfcMGedddaX1rjDDjtkwoQJOfHEE1NTU5O11lorv/jFLxbYt3379unWrVuOPPLIHH/88ampqSnV1L59+5x44on5/e9/nzlz5mSVVVbJySefXNr2yCOPzK9//eusscYa6du3b4YNG5YBAwakWbNm2XfffUvh4vXXX5+2bdvmBz/4wQJrGDZsWK1Tjrfbbrv0798/J598ci655JLMmTMnLVu2zOmnn17rVPAF2WuvvTJ27NgcfvjhWWONNbLTTjvl7rvvTpJad4tu0qRJTjnllAwbNiz33ntvmjVrlpNPPrl0KvaQIUOy9dZbZ+edd/7S4w0AAADwTVJWU1NTU99FLG0zZszIK6+8ko033rgUQNXU1GTatGlp27ZtysrKvvJr7rfffunWrVsOOeSQpV3uN8qrr76al156Kf/1X/+1TMarqakp/b7/9re/5Y477sjQoUOXydgLMmjQoOyzzz455phj6q2GhmpJ5zBQv8xhaNjMYWj4zGNo2OpjDi8oX1sQp0WzTM2aNSs9e/ZcJmO9+OKLOeqoozJjxoxUVVXl8ccf/9JTqQEAAABYfE6LXkxlZWWluxBT3He+851lNtYWW2yRHj16ZNCgQSkvL8+3v/3tHHDAActs/AWprq5OeblMHwAAAFgxCBcX0yqrrJKJEyfWdxl8BWVlZRkwYEAGDBhQ36UkSWbOnJkpU6Z86U14AAAAABoKS6gW0y677JLRo0dn/Pjx9V0KDdRf/vKXVFVVZZdddqnvUgAAAACWCisXF1OfPn3ywAMP5LTTTsuWW26Zjh07plGjRvVdFg3AnDlz8u9//zuvvvpqBgwYULpDOAAAAEBDJ1xcTG3atMkVV1yR22+/PY899lieeOIJ12BksTRt2jTrrbdeDj300Oy55571XQ4AAADAUiNc/ApWWmml5eoafgAAAABQn1xzEQAAAAAoRLgIAAAAABQiXAQAAAAAChEuAgAAAACFCBcBAAAAgEKEiwAAAABAIcJFAAAAAKAQ4SIAAAAAUIhwEQAAAAAoRLgIAAAAABQiXAQAAAAAChEuAgAAAACFCBcBAAAAgEKEiwAAAABAIcJFAAAAAKAQ4SIAAAAAUIhwEQAAAAAoRLgIAAAAABQiXAQAAAAAChEuAgAAAACFCBcBAAAAgEKEiwAAAABAIcJFAAAAAKAQ4SIAAAAAUIhwEQAAAAAoRLgIAAAAABQiXAQAAAAAChEuAgAAAACFCBcBAAAAgEKEiwAAAABAIcJFAAAAAKAQ4SIAAAAAUIhwEQAAAAAoRLgIAAAAABQiXAQAAAAACqnXcHHChAk54ogj0qNHj+y222656KKLUl1dXadfdXV1hg4dmp49e6Z79+7p3bt37rvvvnqoGAAAAACYr3F9Dj548OB07do1Dz/8cCZPnpwjjzwyq6yySg499NBa/W6++ebcdtttueGGG7LuuuvmiSeeyKBBg/Ltb387G220UT1VDwAAAADfbPW2cnHMmDEZN25cTjzxxLRp0yadO3dO//79c+utt9bpO3bs2Gy55Zb59re/nUaNGmW33XbLyiuvnFdffbUeKgcAAAAAknpcuTh27Nh07Ngxbdu2LbV17do148ePz/Tp09O6detS+6677pqzzjorr7zySrp06ZInn3wyM2fOzDbbbLPIMWpqalJTU1Pr5/mPgYbFHIaGzRyGhs0chobPPIaGrT7m8OKOVW/hYkVFRVZaaaVabfODxqlTp9YKF/fYY4+88sor2W+//ZIkLVq0yIUXXpg111xzkWNMnz49lZWVSeYdkBkzZiRJysrKltZuAMuIOQwNmzkMDZs5DA2feQwNW33M4dmzZy9Wv3q95uLiJqB33nln7rzzztx2223ZcMMN8+yzz+aEE07Immuumc0222yh27Vu3TotW7asNVbbtm29kUIDZA5Dw2YOQ8NmDkPDZx5Dw1Yfc3h+mPll6i1cbN++fSoqKmq1VVRUpKysLO3bt6/VfuONN+YnP/lJKUjcdddds+222+buu+9eZLhYVlZW64DPf+yNFBomcxgaNnMYGjZzGBo+8xgatmU9hxd3nHq7ocumm26aiRMnZsqUKaW2MWPGZL311kurVq1q9a2urk5VVVWttjlz5iyTOgEAAACABau3cHGTTTZJt27dMmTIkEyfPj1vvvlmRowYkX79+iVJ9tprr7zwwgtJkp49e+b222/PuHHjMnfu3Dz11FN59tln893vfre+ygcAAACAb7x6vebi0KFDc8YZZ2SHHXZI69at07dv3xxwwAFJkvHjx5fO7T7yyCMzd+7cHH300ZkyZUo6duyYc845J9ttt119lg8AAAAA32j1Gi6uscYaufrqqxf43Kuvvlr6uUmTJjn22GNz7LHHLqPKAAAAAIAvU2+nRQMAAAAADZtwEQAAAAAoRLgIAAAAABQiXAQAAAAAChEuAgAAAACFCBcBAAAAgEKEiwAAAABAIcJFAAAAAKAQ4SIAAAAAUIhwEQAAAAAoRLgI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AADQMCzVG7oAAAAAAN8cX+mGLqNHj17k81OnTl0qRQEAAAAAy7/FDhePPvroTJkyZZF9jjrqqCUuCAAAAABoGBY7XJw+fXomTZr0ddYCAAAAADQgix0ujhw5MieccMJC7xSdJOecc0722WefpVIYAAAAALB8+0rXXFxrrbUW2adFixZLXBAAAAAA0DAsdriYJJMnT17oczU1NZk9e/YSFwQAAAAANAyLHS7269cvd9xxxyL7bL755ktaDwAAAADQQCx2uHjLLbfkJz/5ySL7XHHFFTn88MOXuCgAAAAAYPn3la65uM022yyyzy233LLEBQEAAAAADUP50nyxsrKypflyAAAAAMBybLFXLu65554ZPnz4QgPEmpqadOnSZakVBgAAAAAs375SuAgArHju6N270HY/vOeepVwJAADQ0CzV06IBAAAAgG8O4SIAAAAAUIhwEQAAAAAoRLgIAAAAABQiXAQAAAAAChEuAgAAAACFCBcBAAAAgEKEiwAAAABAIcJFAAAAAKAQ4SIAAAAAUIhwEQAAAAAoRLgIAAAAABQiXAQAAAAAChEuAgAAAACFCBcBAAAAgEKEiwAAAABAIcJFAAAAAKAQ4SIAAAAAUIhwEQAAAAAoRLgIAAAAABQiXAQAAAAACmlc3wWwbN3Ru3eh7X54zz1LuRIAAAAAGjrhIoulaCiZCCYBAAAAVlROiwYAAAAAChEuAgAAAACFCBcBAAAAgEJccxEAaDDcmAwAAJYvVi4CAAAAAIVYuQgAFPJVVxFWVlamSZMmSawkBACAFYWViwAAAABAIfUaLk6YMCFHHHFEevTokd122y0XXXRRqqurF7nNhx9+mO7du2fYsGHLqEoAAAAAYEHq9bTowYMHp2vXrnn44YczefLkHHnkkVlllVVy6KGHLnSbc845J40aNVqGVQIAAAAAC1JvKxfHjBmTcePG5cQTT0ybNm3SuXPn9O/fP7feeutCt3n88cfzxhtvZNddd112hQIAAAAAC1RvKxfHjh2bjh07pm3btqW2rl27Zvz48Zk+fXpat25dq/+sWbPym9/8Jueee27uvPPOxRqjpqYmNTU1tX6e/5hlxzFnaTCHoYGbP3drapKysmU+l713wJLxOQwNn3kMDVt9zOHFHavewsWKioqstNJKtdrmB41Tp06tEy5efvnl2XzzzbPtttsudrg4ffr0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+wEAAAAAy069hYubbrppJk6cmClTppTaxowZk/XWWy+tWrWq03fs2LGlx1VVVfn3v/9dusELAAAAALDs1Vu4uMkmm6Rbt24ZMmRIpk+fnjfffDMjRoxIv379kiR77bVXXnjhhSRJv379cuedd+Zf//pXZs6cmf/5n/9J06ZNs+uuu9ZX+QAAAADwjVev11wcOnRozjjjjOywww5p3bp1+vbtmwMOOCBJMn78+MyYMSNJsvPOO+f444/Psccem8mTJ6dbt24ZPnx4mjdvXp/lAwAAAMA3WlnNV7lTCgAAAADA/1evKxe/ThMmTMhzzz2XNm3aZI011shmm21W3yUBAF9QU1OTsrKy+i4DKMgchoanuro61dXVadz4/+IAcxkajuVxDq+QKxdfffXVHH744dlkk03y4Ycf5tNPP82PfvSj/PznP6/v0oACpkyZko8++iht2rRJu3bt0rJly/ouCSho/PjxeeCBB/Lpp59mq622yo477pimTZvWd1nAYjKHoWF74403MnLkyLz//vvZbrvtsuWWW2aLLbZIUv/hBPDlltc5vMKFi9OnT8+AAQOy55575mc/+1kmTpyY5557LmeccUb69u2b008/vb5LBL6CcePG5Re/+EXat2+f9957LzvuuGP69OmT7bbbrr5LA76i119/PYcccki233771NTU5MEHH8yPfvSj7LfffunevXt9lwd8CXMYGrY333wzBxxwQH7yk5+kefPmeeKJJ9KiRYv07NkzBx10UBIBIyzPluc5vMKdFl1eXp5mzZpl6623TpKsueaa+cEPfpBVVlklgwcPTtOmTXPyySfXc5XA4pg0aVIGDRqUn/70pzn00EPzwAMP5PHHH8+ZZ56Zk046Kb169arvEoHFNGvWrFx22WUZMGBADjvssCTJT37yk1x00UWpqKjI7Nmzs+2229ZzlcDCmMPQsNXU1OTuu+/O/vvvn+OPPz5Jsu++++bWW2/NqFGjMnv27Bx22GGCRVhOLe9zuLxeRv0aVVVV5d13382LL75YaqupqclOO+2Uiy++OH/84x8zatSoeqwQWFwff/xxOnXqlEMPPTRJstdee+Wwww7LrrvumrPPPjuPPvpoPVcILK7mzZunoqIi5eXzvnpUV1dnm222yRlnnJGPP/44t99+e9555516rhJYGHMYGraysrK88847+eCDD0pt6667bg455JDsvPPOefjhh3PPPffUY4XAoizvc3iFCxfbtGmTgQMH5pprrsnDDz+cZN4voaamJrvuumsOOeSQPPXUU5k9e3ZWsDPCYYUxYcKEjBs3LmVlZXnuuefyj3/8o/Rcly5dctBBB6VXr14ZPnx4Xn311XqsFFhcs2fPTqdOnfLee+9l5syZKS8vT01NTTbbbLOccMIJefHFF3P//fcnic9nWI7MmDEjc+fOTWVlZTp16pT333/fHIYGavfdd8+kSZPyz3/+s9S2+uqr58c//nE6d+6cJ598MlVVVfVYIfBFH3/8cf7zn/8kSXr16pWPP/54uZzDK1y4mMxbGrrHHnvksssuy9/+9rdSe+PGjbPuuuvmgw8+SKNGjSz5huXQK6+8kv333z8ffPBBNtpoo3zve9/LTTfdVGs1xDrrrJM+ffqkRYsWeeONN+qxWmBRpk2blgkTJuSTTz5Js2bN0rt379x2223585//nOT//vFviy22yAknnJAbbrghH330kc9nWE68/PLL+elPf5qPP/44TZo0yXe/+93cdtttueOOO5KYw7C8++ijj/Lss89m7NixmTJlSrbddttUVVXljjvuyFtvvVXqt/baa6dv376577778u9//7seKwY+79///nf69u2biRMnJkk22GCDVFVVZdSoUcvdHF4hw8XWrVvn5z//eTbddNNceOGF+ctf/lL6kvPJJ5+kdevWqaysrOcqgS8aN25cDj744PTv3z89e/ZMkuy5556ZNGlSbr311rz33nulvptttlk6dOhQWqEMLF/GjRuXAw88MCeccEL22muvXHLJJfnWt76V888/P+eee25uu+22Whec3mSTTbLeeuulefPm9Vw5kMybwwMGDEivXr2yxhprJEl23XXXnHjiieYwNADjxo3LAQcckMsvvzyDBw/OL37xi7z99ts566yz8vTTT+eGG27IuHHjSv0333zz9OjRI02aNKnHqoH5xo0bl0MOOSQ//vGPSzdNW3/99XPUUUctl3N4hbuhy3yrrbZajj/++Nxwww055ZRTcscdd6Rly5Z59tlnM3LkyLRo0aK+SwQ+Z/6b55FHHpnDDjsslZWVeeSRR9KiRYs0b94877zzTm644Yb069cvXbp0SZLSf+wAy5cPP/wwRx11VA488MDsv//+ueeee/LYY4/lhBNOyPHHH59zzz03v/zlL/Pxxx9n9913z/rrr58nn3wyFRUVqa6uru/y4Rtv/j/2HX744Tn88MNTU1OT999/P02bNs0hhxySZs2a5YwzzsikSZPSq1cvcxiWM1OmTMlxxx2XAw88MP37988LL7yQRx55JP3798/ll1+eyy+/PCeeeGI++eST7Lbbbvne976XG264Ia+99lratWtX3+XDN978/zY+/PDDc8QRR6S6ujrPP/98mjZtmu7du+f3v/99Tj311OVqDpfVfAMuijJ69Og8++yzadmyZXbYYYd8+9vfru+SgM+prKzMPvvskxYtWuTuu+9OVVVV+vTpk7KysjRu3Dj/+c9/UllZme233z7vvvtudtlll1RWVubmm2/OLbfckg033LC+dwH4nGeeeSYjR47MlVdeWWp77rnncvvtt+e9997Lueeem3feeScXX3xxkmTVVVfNq6++mmuvvTabbrppfZUNZF4osffee2f33XfPueeem8rKyhx00EGZO3du3n333Xz3u9/NgAED8sEHH+SCCy5IYg7D8ub999/PqaeemmHDhpWChmnTpuWPf/xjLr300lx33XVZe+21M3z48Dz66KNZZ511MmnSpAwdOtQchno2ffr07LHHHtl8881zxRVXZM6cOfmv//qv1NTUZMqUKWnatGl+85vfpFOnTrnqqqvyyCOPpFOnTvU+h78R4SKw/Bs9enQOOeSQ0n/AVFRU5LzzzsukSZMy7v+1d7cxVZd/HMc/4AkMRBBRSMFKlCMqpA+o8IERdsNKp1NIW5NiRW7NzKyoOa2FrnJaimg2oqWAiKLiRIXKu9hYscyKuea9eYC4EQSBxLg5/B8Yv794H5K/g75fjw7XdfjxPWxfdvic67p+hw9r3rx5Cg8PV2RkpHbt2iVfX1+98MILGjFihNmlA7hMYWGhZs+efUX4f/DgQaWlpUmSli1bprKyMlVUVKihoUHBwcEaPHiwWSUD+IfNZlNqaqqqqqoUHx+vzMxMtbW1ad68efrxxx9VWFiompoaJSUlqampSWVlZfQw4GDKy8v11FNPKTk5WREREcZ4U1OTUlNTtWnTJqWmpspqtaqyslKNjY3q16+fvL29zSsagCE7O1uJiYlasmSJDh06pOrqai1evFhHjx7V/v379cUXX+irr77SI4884jA9TLgIwGEUFxcrNjZW/v7+WrlyZadVxunp6crJyVFW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",
"text/plain": [
"<Figure size 1600x800 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"📊 序列预测结果统计:\n",
" 预测位点总数: 85\n",
" 高概率位点 (>0.8): 0\n",
" 中概率位点 (0.4-0.8): 6\n",
" 最高预测概率: 0.475\n"
]
}
],
"source": [
"# Select a sequence for demonstration\n",
"from Bio import SeqIO\n",
"\n",
"# Read the first mRNA sequence for demonstration\n",
"mrna_sequences = list(SeqIO.parse(mrna_file, \"fasta\"))\n",
"demo_seq = mrna_sequences[0] # Select the first sequence\n",
"\n",
"print(f\"🧬 Selected demonstration sequence: {demo_seq.id}\")\n",
"print(f\"Sequence length: {len(demo_seq.seq)} bp\")\n",
"print(f\"First 100bp of sequence: {str(demo_seq.seq)[:100]}...\")\n",
"\n",
"# Use built-in plot_prf_prediction function for prediction and visualization\n",
"print(f\"\\n🎯 Using plot_prf_prediction for sequence prediction and visualization...\")\n",
"\n",
"sequence_results, fig = plot_prf_prediction(\n",
" sequence=str(demo_seq.seq),\n",
" window_size=3,\n",
" short_threshold=0.2,\n",
" long_threshold=0.2,\n",
" ensemble_weight=0.6,\n",
" title=f\"PRF Prediction Results for Sequence {demo_seq.id} (Bar Chart + Heatmap)\",\n",
" figsize=(16, 8),\n",
" dpi=150\n",
")\n",
"\n",
"plt.show()\n",
"\n",
"print(f\"\\n📊 Sequence prediction result statistics:\")\n",
"print(f\" Total predicted sites: {len(sequence_results)}\")\n",
"print(f\" High probability sites (>0.8): {(sequence_results['Ensemble_Probability'] > 0.8).sum()}\")\n",
"print(f\" Medium probability sites (0.4-0.8): {((sequence_results['Ensemble_Probability'] >= 0.4) & (sequence_results['Ensemble_Probability'] <= 0.8)).sum()}\")\n",
"print(f\" Highest prediction probability: {sequence_results['Ensemble_Probability'].max():.3f}\")"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"🔝 Top 5 预测位点:\n",
" 1. 位置 96: \n",
" - Short概率: 0.288\n",
" - Long概率: 0.755\n",
" - 集成概率: 0.475\n",
" - 密码子: TAA\n",
" 2. 位置 12: \n",
" - Short概率: 0.606\n",
" - Long概率: 0.177\n",
" - 集成概率: 0.434\n",
" - 密码子: TTG\n",
" 3. 位置 15: \n",
" - Short概率: 0.493\n",
" - Long概率: 0.329\n",
" - 集成概率: 0.428\n",
" - 密码子: GAA\n",
" 4. 位置 18: \n",
" - Short概率: 0.369\n",
" - Long概率: 0.510\n",
" - 集成概率: 0.426\n",
" - 密码子: GTC\n",
" 5. 位置 105: \n",
" - Short概率: 0.248\n",
" - Long概率: 0.671\n",
" - 集成概率: 0.418\n",
" - 密码子: ACT\n",
"\n",
"📊 可视化分析完成!\n",
"图表包含热图和条形图展示了整个序列的PRF预测概率分布。\n"
]
}
],
"source": [
"# Print top predicted site probabilities\n",
"if sequence_results['Ensemble_Probability'].max() > 0.3:\n",
" top_predictions = sequence_results.nlargest(5, 'Ensemble_Probability')\n",
" print(f\"\\n🔝 Top 5 predicted sites:\")\n",
" for i, (_, row) in enumerate(top_predictions.iterrows(), 1):\n",
" print(f\" {i}. Position {row['Position']}: \")\n",
" print(f\" - Short probability: {row['Short_Probability']:.3f}\")\n",
" print(f\" - Long probability: {row['Long_Probability']:.3f}\")\n",
" print(f\" - Ensemble probability: {row['Ensemble_Probability']:.3f}\")\n",
" print(f\" - Codon: {row['Codon']}\")\n",
"else:\n",
" print(\"\\n💡 No high-probability PRF sites detected in this sequence\")\n",
"\n",
"print(\"\\n📊 Visualization analysis complete!\")\n",
"print(\"The chart contains heatmaps and bar charts showing the PRF prediction probability distribution across the entire sequence.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 📝 Analysis Summary\n",
"\n",
"### 🎯 Key Findings\n",
"1. **Data Quality**: Test dataset contains real BLASTX alignment results and validation regions\n",
"2. **FScanR Performance**: Successfully identified potential PRF sites from BLASTX results\n",
"3. **Model Performance**: Short and Long models each have advantages in different scenarios\n",
"4. **Prediction Results**: Ensemble model provides more stable prediction performance\n",
"5. **Visualization**: Built-in plotting functions generate clear heatmaps and bar charts\n",
"\n",
"### 🔧 Best Practices\n",
"- **Data Preprocessing**: Ensure BLASTX results are in correct format\n",
"- **Parameter Settings**: Use default ensemble weights (0.4:0.6) for balanced performance\n",
"- **Result Interpretation**: When using FScanpy for whole sequence prediction, don't use 0.5 as threshold, but compare relative probabilities across positions\n",
"- **Visualization**: Use plot_prf_prediction function to generate standardized plots\n",
"\n",
"### 📚 Usage Recommendations\n",
"1. **Threshold Selection**: Adjust probability thresholds based on application scenarios\n",
"2. **Result Validation**: Validate prediction results with biological knowledge\n",
"3. **Performance Optimization**: Use reasonable sliding window sizes for large-scale data\n",
"4. **Visualization Parameters**: Adjust figsize and dpi for optimal display"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "tf200",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}