科研绘图系列:基因突变瀑布图统计以及可视化

在这里插入图片描述

介绍

基因突变瀑布图是一种用于展示基因组突变数据的可视化图表,它能够直观地展示每个样本中的突变情况,包括突变类型和突变基因。以下是瀑布图的主要特点和它能说明的问题:

  1. 展示突变信息:瀑布图的中间主体部分横坐标代表样本,纵坐标代表基因,颜色条块表示该基因在该样本中发生了突变,不同的颜色代表不同的突变类型。
  2. 突变数目统计:瀑布图最上面的柱状图表示每个样本的突变数目,可以快速了解样本中的突变频率。
  3. 基因突变类型统计:瀑布图最右侧的条形图表示每个基因不同突变类型的数目,有助于识别特定基因的突变类型分布。
  4. 样本和基因的排序:瀑布图通过排序可以展示突变个数最多的基因和包含这些基因突变的样本,有助于识别高频突变基因和样本。
  5. 突变类型的展示:瀑布图可以展示不同类型的突变,如错义突变、移码突变、无义突变、插入缺失等,有助于理解突变的性质和影响。
  6. 临床信息的关联:瀑布图还可以对样本进行临床信息的注释,观察临床信息与基因突变的相关性趋势。
  7. 发现潜在的驱动基因:通过识别样本中高频突变的基因,瀑布图有助于发现可能的肿瘤驱动基因。
  8. 趋势性和互斥伴发现象:瀑布图可以揭示某些基因突变之间的趋势性互斥伴发现象,这对于理解疾病机理和基因相互作用具有重要意义。

数据下载

MongolianHCC数据集:

  • 百度网盘链接: https://pan.baidu.com/s/15BE0QMCXKs6VYthZBTZyeQ
  • 提取码: dazy

在这里插入图片描述

加载R包

library(maftools)
library(TCGAmutations)
library(circlize)
library(ComplexHeatmap)
library(RColorBrewer)
library(openxlsx)
library(dplyr)

代码

PROJECT_DIR <- "./MongolianHCC/" # replace this line with your local path

source(file.path(PROJECT_DIR, "SCRIPTS", "helper_functions.oncoplot.R"))

sample_info_file <- file.path(PROJECT_DIR, "DATA", "PROCESSED", "patient_sample_metadata_w_clustering_risk.txt")
driver_res_file <- file.path(PROJECT_DIR, "DATA", "ORIGINAL", "mut_full.sig_genes.txt")

out_dir <- file.path(PROJECT_DIR, "RESULTS", "mut_oncoplot")
maf_file <- file.path(PROJECT_DIR, "DATA", "PROCESSED", "maf_after_all_filters.maf")
sample_info.exome.file <- sample_info_file

driver_results_file <- driver_res_file
driver_sig_col <- "q"
driver_sig_thresh <- 0.1
driver_sig_freq <- 0.05
cohort_freq_thresh <- 0.2
# cohort_freq_thresh=NA
gene_list_file <- NA

source(file.path(PROJECT_DIR, "SCRIPTS", "helper_functions.oncoplot.R"))

if (!dir.exists(out_dir)) {
  dir.create(out_dir, recursive = T)
}

if (grepl(".xlsx$", sample_info.exome.file)) {
  library(openxlsx)
  sample_info.exome <- read.xlsx(sample_info.exome.file)
} else {
  sample_info.exome <- read.table(sample_info.exome.file, sep = "\t", header = T, stringsAsFactors = F)
  sample_info.exome$Tumor_Sample_Barcode <- sample_info.exome$WES_T
}

ignoreGenes <- c("TTN", "MUC16", "OBSCN", "AHNAK2", "SYNE1", "FLG", "MUC5B", 
                 "DNAH17", "PLEC", "DST", "SYNE2", "NEB", "HSPG2", "LAMA5", 
                 "AHNAK", "HMCN1", "USH2A", "DNAH11", "MACF1", "MUC17", "DNAH5", 
                 "GPR98", "FAT1", "PKD1", "MDN1", "RNF213", "RYR1", "DNAH2", 
                 "DNAH3", "DNAH8", "DNAH1", "DNAH9", "ABCA13", "SRRM2", "CUBN", 
                 "SPTBN5", "PKHD1", "LRP2", "FBN3", "CDH23", "DNAH10", "FAT4", 
                 "RYR3", "PKHD1L1", "FAT2", "CSMD1", "PCNT", "COL6A3", "FRAS1", 
                 "FCGBP", "RYR2", "HYDIN", "XIRP2", "LAMA1")
# sort(ignoreGenes)

mafObj <- read.maf(maf_file, clinicalData = sample_info.exome)
maf.filter <- mafObj

frac_mut <- data.frame(
  Hugo_Symbol = maf.filter@gene.summary$Hugo_Symbol,
  frac_mut = (maf.filter@gene.summary$MutatedSamples / as.numeric(maf.filter@summary$summary[3])),
  stringsAsFactors = F
)
frac_mut[is.na(frac_mut)] <- 0

# driver_res_file="data/somatic.sig_genes.txt"
# driver_sig_col="q"
# driver_sig_thresh=0.1
# driver_sig_freq=0.05
if (file.exists(driver_res_file)) {
  driver_res <- read.table(driver_res_file, sep = "\t", header = T, quote = "", stringsAsFactors = F)
  colnames(driver_res)[colnames(driver_res) == "gene"] <- "Hugo_Symbol"
  driver_res$FLAG_gene <- driver_res$Hugo_Symbol %in% ignoreGenes
  driver_res_plus <- merge.data.frame(driver_res, frac_mut)
  driver_res_plus <- driver_res_plus[order(driver_res_plus[, driver_sig_col], decreasing = F), ]
  driver_genes <- driver_res_plus$Hugo_Symbol[driver_res_plus[, driver_sig_col] < driver_sig_thresh & driver_res_plus$frac_mut > driver_sig_freq]
} else {
  driver_res_plus <- frac_mut
  driver_genes <- c()
}

# driver_res_plus <- driver_res
cohort_freq_thresh <- 0.1
if (!is.na(cohort_freq_thresh)) {
  freq_genes <- setdiff(driver_res_plus$Hugo_Symbol[driver_res_plus$frac_mut > cohort_freq_thresh], driver_genes)
} else {
  freq_genes <- NULL
}

if (file.exists(as.character(gene_list_file))) {
  custom_gene_list <- read.table(gene_list_file, stringsAsFactors = F)[, 1]
  custom_gene_list <- setdiff(custom_gene_list, c(driver_genes, freq_genes))
} else {
  custom_gene_list <- NULL
}

gene_list <- list(driver_genes, freq_genes, custom_gene_list)
reasons <- c(
  paste0("Driver Gene, ", driver_sig_col, " < ", driver_sig_thresh),
  paste0("Cohort Freq > ", cohort_freq_thresh),
  paste0("Selected Genes")
)

genes_for_oncoplot <- data.frame(Hugo_Symbol = c(), reason = c())
for (i in 1:length(gene_list)) {
  if (is.null(gene_list[[i]][1])) {
    next
  }
  genes_for_oncoplot <- rbind(
    genes_for_oncoplot,
    data.frame(
      Hugo_Symbol = gene_list[[i]],
      reason = reasons[i]
    )
  )
}
genes_for_oncoplot <- cbind(genes_for_oncoplot,
  frac = driver_res_plus$frac_mut[match(genes_for_oncoplot$Hugo_Symbol, driver_res_plus$Hugo_Symbol)]
)

genes_for_oncoplot <- genes_for_oncoplot[!is.na(genes_for_oncoplot$frac), ]
genes_for_oncoplot <- genes_for_oncoplot[order(genes_for_oncoplot$reason, -genes_for_oncoplot$frac), ]
split_idx <- as.character(genes_for_oncoplot$reason)
split_idx <- factor(split_idx, levels = reasons[reasons %in% split_idx])
split_colors <- rainbow(length(levels(split_idx)))
names(split_colors) <- as.character(genes_for_oncoplot$reason[!duplicated(genes_for_oncoplot$reason)])
split_colors <- list(Reason = split_colors)

# source("scripts/helper_functions.R")
oncomat <- createOncoMatrix(maf.filter, g = genes_for_oncoplot$Hugo_Symbol, add_missing = F)$oncoMatrix
write.table(genes_for_oncoplot, file = paste0(out_dir, "/genes_for_oncoplot.txt"), sep = "\t", quote = F, row.names = F)

include_all <- T
if (include_all) {
  ### createOncoMatrix drops empty samples, so this adds them back in
  all_wes_samples <- as.character(sample_info.exome$Tumor_Sample_Barcode[!is.na(sample_info.exome$Tumor_Sample_Barcode)])
  extra_samples <- setdiff(all_wes_samples, colnames(oncomat))
  empty_data <- matrix(data = "", nrow = nrow(oncomat), ncol = length(extra_samples), dimnames = list(rownames(oncomat), extra_samples))
  oncomat <- cbind(oncomat, empty_data)
}

oncomat <- oncomat[match(genes_for_oncoplot$Hugo_Symbol, rownames(oncomat)), ]
onco_genes <- rownames(oncomat)

#### TCGA Comparison Heatmap (from helper_functions.oncoplot.R)
tcga_comparison_results <- make_TCGA_comparison_heatmap(onco_genes, maf.filter, split_at = split_idx)
tcga_comparison_hm <- tcga_comparison_results[[1]]


#### MONGOLIA oncoplot
## Oncoplot parameters
annotate_empty <- ""
annotation_font_size <- 9
annotation_height_frac <- 0.3
onco_width <- 9
onco_height <- NULL

oncomat.plot <- oncomat
colnames(oncomat.plot) <- sample_info.exome$Patient[match(colnames(oncomat.plot), sample_info.exome$Tumor_Sample_Barcode)]

if (is.null(onco_height)) {
  onco_height <- max(round(0.2 * nrow(oncomat.plot), 0) + 2, 5)
}

hm_anno_info <- as.data.frame(sample_info.exome[match(colnames(oncomat.plot), sample_info.exome$Patient), ])
rownames(hm_anno_info) <- hm_anno_info$Patient
hm_anno_info <- hm_anno_info[, c(10:ncol(hm_anno_info))]
hm_anno_info$sex <- ifelse(is.na(hm_anno_info$sex), "NA", ifelse(hm_anno_info$sex == 1, "M", "F"))


grouping_var <- "hdv"
group_counts <- c(0, table(hm_anno_info[, grouping_var], useNA = "ifany"))
names(group_counts) <- c(names(group_counts)[2:length(group_counts)], "last")
group_levels <- sort(unique(hm_anno_info[, grouping_var]))
plot_idx <- c()
for (currgroup_idx in 1:length(group_levels)) {
  # currgroup_idx=1
  currgroup <- group_levels[currgroup_idx]
  curr_subset <- hm_anno_info[hm_anno_info[, grouping_var] == currgroup, ]
  order_classes <- factor(ifelse(is.na(as.character(curr_subset$class)), "Unknown", as.character(curr_subset$class)))
  curr_idx <- orderByGroup(oncomat.plot[, colnames(oncomat.plot) %in% rownames(curr_subset)], order_classes)
  plot_idx <- c(
    plot_idx,
    rownames(curr_subset)[curr_idx]
  )
}

plot_order <- plot_idx

################### TOGGLE FOR TOP/BOTTOM ANNOTATION ###################
##### This is for only class/cluster on top
# top_anno_names <- c("Class")
# names(top_anno_names) <- c("class")
# bot_anno_names <- c("Sex","Age","HCV","HBV","HDV","Stage","Tumor Size","Cirrhosis","Obesity","Alcohol","Smoker","Family History","alb","bil","alt","afp","multinodular","Risk Group")
# names(bot_anno_names) <- c("sex","age_bin","hcv","hbv","hdv","stage","tumor_size","cirrhosis","obesity","alcohol","smoker","FHx_LC","alb","bil","alt","afp","multinodular","risk_bin") # column names
################### TOGGLE FOR TOP/BOTTOM ANNOTATION ###################
##### This is for cluster+HDV on top
top_anno_names <- c("Class", "HDV", "HBV", "HCV")
names(top_anno_names) <- c("class", "hdv", "hbv", "hcv")
bot_anno_names <- c(
  "Sex", "Age", "Obesity", "Smoking", "Alcohol", "Family History", "Cirrhosis",
  "alb", "bil", "alt", "afp", "Tumor Size", "multinodular", "Stage", "Risk Group"
)

names(bot_anno_names) <- c("sex", "age_bin", "obesity", "smoker", "alcohol", 
                           "FHx_LC", "cirrhosis", "alb", "bil", "alt", "afp", 
                           "tumor_size", "multinodular", "stage", "risk_bin") # column names
########################################################################


hm_anno_info <- hm_anno_info[, unique(c(names(top_anno_names), names(bot_anno_names)))]

annocolors <- my_oncoplot_colors(hm_anno_info)


my_types <- unique(unlist(apply(oncomat.plot, 2, unique)))
my_types <- my_types[!my_types %in% c(NA, "", 0)]

col <- c(
  Nonsense_Mutation = "#ad7aff", 
  Missense_Mutation = "#377EB8", 
  Frame_Shift_Del = "#4DAF4A",
  In_Frame_Ins = "#ff008c", 
  Splice_Site = "#FF7F00", 
  Multi_Hit = "#FFFF33", 
  Frame_Shift_Ins = "#A65628",
  In_Frame_Del = "#f781bf", 
  Translation_Start_Site = "#400085", 
  Nonstop_Mutation = "#b68dfc",
  no_variants = "#d6d6d6"
)

top_anno_data <- data.frame(hm_anno_info[, names(top_anno_names)], row.names = rownames(hm_anno_info))
colnames(top_anno_data) <- names(top_anno_names)
bot_anno_data <- data.frame(hm_anno_info[, names(bot_anno_names)], row.names = rownames(hm_anno_info))
colnames(bot_anno_data) <- names(bot_anno_data)

unmutated_annodata <- ifelse(colSums(nchar(oncomat.plot)) == 0, annotate_empty, "")

annocolors$empty <- c("TRUE" = "black", "FALSE" = "white")
top_height <- onco_height * annotation_height_frac * (ncol(top_anno_data) / ncol(bot_anno_data))
top_anno <- HeatmapAnnotation(
  empty = anno_text(
    unmutated_annodata, 
    gp = gpar(fontsize = 6, fontface = "bold", col = "grey10"), 
    location = unit(0.5, "npc"),
    which = "column"),
  df = top_anno_data, 
  name = "top_anno", 
  col = annocolors, 
  show_annotation_name = T, 
  na_col = "grey70", 
  show_legend = F,
  simple_anno_size_adjust = T, 
  height = unit(top_height, "inches"), 
  annotation_name_gp = gpar(fontsize = annotation_font_size)
)
names(top_anno) <- top_anno_names[names(top_anno)]

bot_anno <- HeatmapAnnotation(
  df = bot_anno_data, 
  name = "bot_anno", 
  col = annocolors, 
  show_annotation_name = T, 
  na_col = "white", 
  show_legend = F,
  simple_anno_size_adjust = T, 
  height = unit(onco_height * annotation_height_frac, "inches"),
  annotation_name_gp = gpar(fontsize = annotation_font_size)
)
names(bot_anno) <- bot_anno_names[names(bot_anno)]


# browser()
names(col) <- gsub("_", " ", names(col))
oncomat.plot <- gsub("_", " ", oncomat.plot)

col_split_idx <- hm_anno_info$hdv
onco_base_default <- oncoPrint(
  oncomat.plot,
  alter_fun = alter_fun, 
  col = col, 
  row_order = 1:nrow(oncomat.plot),
  name = "oncoplot",
  show_pct = F,
  top_annotation = top_anno,
  bottom_annotation = bot_anno,
  row_split = split_idx,
  left_annotation = rowAnnotation(Reason = split_idx, col = split_colors, annotation_width = unit(0.2, "mm")),
  row_title = NULL,
  column_title = NULL,
  column_order = plot_order,
  column_gap = unit(0.01, "npc"),
  column_split = col_split_idx,
  width = 1
)

# browser()
save_name <- paste0(out_dir, "/oncoplot.pdf")

pdf(file = save_name, height = onco_height, width = onco_width)
draw(tcga_comparison_hm + onco_base_default, main_heatmap = 2)

class_labels <- hm_anno_info$class[match(plot_order, rownames(hm_anno_info))]
class_labels[is.na(class_labels)] <- "NA"
class_labels <- factor(class_labels)

slice_labels <- hm_anno_info$hdv[match(plot_order, rownames(hm_anno_info))]
slice_labels[is.na(slice_labels)] <- "NA"
slice_labels <- factor(slice_labels)

myclasses <- split(class_labels, slice_labels)
label_idx <- lapply(myclasses, function(x) {
  # x=myclasses[[1]]
  change_idx <- c(which(as.logical(diff(as.numeric(x)))), length(x))
  change_idx <- change_idx / length(x)
  curr_label_idx <- rep(1, length(change_idx))
  for (i in 1:length(change_idx)) {
    prev_start <- ifelse(length(change_idx[i - 1]) > 0, change_idx[i - 1], 0)
    curr_label_idx[i] <- (change_idx[i] - prev_start) / 2 + prev_start
  }
  mynames <- ifelse(diff(c(0, change_idx)) < 0.1, "", levels(x))
  names(curr_label_idx) <- mynames
  return(curr_label_idx)
})

## Add cluster labels to top annotation
for (slice_num in 1:length(label_idx)) {
  for (class_num in 1:length(label_idx[[slice_num]])) {
    labeltxt <- names(label_idx[[slice_num]])[class_num]
    labelpos <- label_idx[[slice_num]][class_num]
    decorate_annotation("Class", slice = slice_num, {
      grid.text(labeltxt, labelpos,
        0.5,
        default.units = "npc", gp = gpar(fontsize = annotation_font_size * 0.9, fontface = "italic", col = "white")
      )
    })
  }
}

dev.off()


####  TABLE containing data for each variant
output_data <- maf.filter@data[maf.filter@data$Hugo_Symbol %in% onco_genes, ]
output_data$tumor_genotype <- apply(output_data[, c("Tumor_Seq_Allele1", "Tumor_Seq_Allele2")], 1, paste, collapse = "/")
output_data$normal_genotype <- apply(output_data[, c("Match_Norm_Seq_Allele1", "Match_Norm_Seq_Allele2")], 1, paste, collapse = "/")

pheno_info <- sample_info.exome[match(output_data$Tumor_Sample_Barcode, sample_info.exome$Tumor_Sample_Barcode), ]
pheno_info <- cbind(pheno_info[, "Tumor_Sample_Barcode"], pheno_info[, -c("Tumor_Sample_Barcode")])
pheno_columns <- colnames(pheno_info)
names(pheno_columns) <- make.names(pheno_columns, unique = T)

output_data <- cbind(output_data, pheno_info)
cols_for_table <- c(
  "Hugo Symbol" = "Hugo_Symbol",
  "Variant Classification" = "Variant_Classification",
  "Variant Type" = "Variant_Type",
  "Consequence" = "Consequence",
  "Chromosome" = "Chromosome", "Start Position" = "Start_Position", "End Position" = "End_Position", "Strand" = "Strand",
  "Reference Allele" = "Reference_Allele",
  "Tumor Genotype" = "tumor_genotype",
  "Normal Genotype" = "normal_genotype",
  "Transcript Change" = "HGVSc",
  "Protein Change" = "HGVSp_Short",
  "Normal Depth" = "n_depth",
  "Normal Ref Depth" = "n_ref_count",
  "Normal Alt Depth" = "n_alt_count",
  "Tumor Depth" = "t_depth",
  "Tumor Ref Depth" = "t_ref_count",
  "Tumor Alt Depth" = "t_alt_count",
  "Existing Annotation" = "Existing_variation",
  "gnomAD Frequency" = "gnomAD_AF",
  "ExAC Frequency" = "ExAC_AF",
  "1000Genomes Frequency" = "AF",
  "Current Cohort Frequency" = "tumor_freq",
  pheno_columns
)

variant_info <- as.data.frame(output_data)[, cols_for_table]
colnames(variant_info) <- names(cols_for_table)
write.xlsx(variant_info, file = paste0(out_dir, "/Table_2.xlsx"))

tcga.white <- tcga_comparison_results[[2]]
tcga.asian <- tcga_comparison_results[[3]]
tcga_lihc_mc3 <- tcga_comparison_results[[4]]
all_dfs <- list(
  driver_res_plus,
  data.frame(
    MONG_frac_mut = (maf.filter@gene.summary$MutatedSamples / as.numeric(maf.filter@summary$summary[3])),
    Hugo_Symbol = maf.filter@gene.summary$Hugo_Symbol, stringsAsFactors = F
  ),
  data.frame(
    TCGA_All_frac_mut = (tcga_lihc_mc3@gene.summary$MutatedSamples / as.numeric(tcga_lihc_mc3@summary$summary[3])),
    Hugo_Symbol = tcga_lihc_mc3@gene.summary$Hugo_Symbol, stringsAsFactors = F
  ),
  data.frame(
    TCGA_Asian_frac_mut = (tcga.asian@gene.summary$MutatedSamples / as.numeric(tcga.asian@summary$summary[3])),
    Hugo_Symbol = tcga.asian@gene.summary$Hugo_Symbol, stringsAsFactors = F
  ),
  data.frame(
    TCGA_White_frac_mut = (tcga.white@gene.summary$MutatedSamples / as.numeric(tcga.white@summary$summary[3])),
    Hugo_Symbol = tcga.white@gene.summary$Hugo_Symbol, stringsAsFactors = F
  ),
  data.frame(maf.filter@gene.summary)
)


all_dfs_merged <- all_dfs %>%
  Reduce(function(dtf1, dtf2) left_join(dtf1, dtf2, by = "Hugo_Symbol"), .)

write.xlsx(all_dfs_merged, file = paste0(out_dir, "/gene_mutsig_info.xlsx")) # ,asTable = T)

在这里插入图片描述

参考

  • The genomic landscape of Mongolian hepatocellular carcinoma
<think>好的,我现在需要帮助用户查找关于信号瀑布的相关信息和实现方式。用户提到了几个引用来源,其中引用[3]和[4]涉及到Origin、R-maftools、matlab和qcustomplot等工具。首先,我需要理解什么是信号瀑布。 信号瀑布通常用于展示信号随时间或频率的变化,比如在振动分析或频谱分析中,不同时间段的频谱可以叠加显示,形成类似瀑布的层次感。根据引用[4],matlab可以用来绘制振动信号的瀑布,显示不同时间段的频谱。引用[3]则提到Origin通过调整坐标轴和散点设置来生成瀑布,而引用[2]和[1]虽然涉及瀑布,但主要是关于基因突变绘图的教程,可能相关性较低。 接下来,用户需要实现方法、示例代码和工具推荐。我需要整理不同工具的实现步骤,比如在Origin中如何调整数据表和坐标轴,matlab中如何编程处理信号并绘图。同时,需要确保代码示例正确,比如matlab中使用meshgrid和surf函数,以及Python的Matplotlib库。还要注意用户提到的系统级指令,比如数学表达式的格式和引用标注。 在回答结构上,应该先介绍信号瀑布的概念和应用,再分工具说明实现方法,并提供代码示例。最后推荐工具并附上相关问题。需要检查每个步骤是否符合用户的要求,特别是引用来源是否正确标注,例如引用[3]和[4]对应的内容是否准确。此外,确保所有数学表达式如$f(t)$和代码块格式正确,使用中文回答,并生成相关问题。</think>### 信号瀑布实现方法及工具 信号瀑布用于可视化信号在不同时间或频率上的动态变化,常见于振动分析、声学测量和通信系统等领域。以下是不同工具的实现方法及示例代码: --- #### **1. MATLAB实现** **实现步骤**: 1. **信号分段**:将时域信号按时间段分割 2. **频谱计算**:对每段信号进行FFT变换 3. **三维绘图**:用瀑布叠加显示各段频谱 **示例代码**: ```matlab % 生成模拟信号 fs = 1000; % 采样率 t = 0:1/fs:2; f = 10; % 信号频率 x = sin(2*pi*f*t); % 分段计算频谱 n_segments = 10; spectra = []; for i = 1:n_segments segment = x((i-1)*200+1 : i*200); Y = fft(segment); P = abs(Y/length(Y)); spectra = [spectra; P(1:100)']; % 取前一半频谱 end % 绘制瀑布 [X, Y] = meshgrid(1:size(spectra,2), 1:n_segments); waterfall(X, Y, spectra); xlabel('频率分量'); ylabel('时间段'); zlabel('幅值'); ``` **效果**:三维视展示不同时间段的频谱分布[^4]。 --- #### **2. Origin实现** **实现步骤**(引用[3]): 1. **数据表结构**:将不同时间段的频谱数据按XY列排列 2. **绘制点线**:全选数据生成普通2D 3. **转换为瀑布**: - 调整右侧坐标轴为注释(如时间段标签) - 修改线条为点线,符号设为球形 - 颜色映射表示幅值强度 4. **3D扩展**:通过“3D瀑布”选项增强立体效果 **关键操作**: - 双击曲线 → 调整线型/符号 → 右侧坐标轴标题改为“时间段”[^3] --- #### **3. Python实现(Matplotlib)** **示例代码**: ```python import numpy as np import matplotlib.pyplot as plt # 生成模拟信号 t = np.linspace(0, 2, 1000) frequencies = [10, 20, 30] spectra = [] for i in range(10): y = np.sum([np.sin(2*np.pi*f*(t + i*0.1)) for f in frequencies], axis=0) fft_result = np.fft.fft(y) spectra.append(np.abs(fft_result[:500])) # 绘制瀑布 fig = plt.figure() ax = fig.add_subplot(111, projection='3d') for i, spec in enumerate(spectra): ax.plot(np.arange(500), np.ones(500)*i, spec) ax.set_xlabel('频率') ax.set_ylabel('时间段') ax.set_zlabel('幅值') plt.show() ``` --- #### **工具推荐** 1. **MATLAB**:适合处理大规模信号及复杂频谱分析 2. **Origin**:交互式操作简单,适合快速生成发表级表[^3] 3. **Python(Matplotlib)**:灵活性强,适合自定义可视化需求 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

生信学习者1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值