<p>After a lot of experimentation with the various parameters I was able to get a heatmap that is rather close to the one generated by Seurat!</p>
<pre><code># Unique is used to eliminate duplicated genes,
# this is done automatically by Seurat DoHeatmap
features &lt;- unique(most_significant_other_cells_markers$gene)

# Extract the expression data for the selected genes from the scaled layer
expr_matrix &lt;- as.matrix(
  GetAssayData(
    breast_cancer_patients_other_cells, 
    layer = &quot;scale.data&quot;, 
    assay = &quot;SCT&quot;
  )[
    features,
  ]
)

# Prepare cell type annotations
cell_types &lt;- Idents(breast_cancer_patients_other_cells)
# Create vector with unique and sorted cell types
unique_cell_types &lt;- sort(unique(cell_types))

# Create color palette for cell types
cell_type_colors &lt;- setNames(
  gg_color_hue(length(unique_cell_types)),
  unique_cell_types
)

# Recreate the Seurat expression scale
palette_expression_level = circlize::colorRamp2(
  c(min(expr_matrix), median(expr_matrix), min(2.5, max(expr_matrix))),
  c(&quot;#FF00FF&quot;, &quot;#000000&quot;, &quot;#FFFF00&quot;))

# Create the heatmap with ComplexHeatmap
ht = Heatmap(
  matrix = expr_matrix,
  row_order = features,
  name = &quot;expression&quot;,
  column_split = factor(cell_types, levels = unique_cell_types),
  # Do not cluster rows or columns otherwise row_order/column_order are ignored
  cluster_rows = FALSE,
  cluster_columns = FALSE,
  column_title_rot = 0,
  show_column_names = FALSE,
  show_column_dend = FALSE,
  show_row_names = TRUE,
  show_row_dend = FALSE,
  cluster_column_slices = TRUE,
  column_gap = unit(0.5, &quot;mm&quot;),
  row_names_gp = gpar(fontsize = 5),
  # The column title can be either a title for all the columns
  # or a vector with a name for every column
  column_title = unique_cell_types,
  column_title_gp = gpar(fontsize = 7),
  # Add the annotation bars on top
  top_annotation = HeatmapAnnotation(
    # Give a name to the annotation, not used on the actual plot
    name = &quot;Clusters&quot;,
    # Annotate the columns
    which = &quot;column&quot;,
    # First annotation - clusters
    cluster = cell_types,
    # Second annotation - patients
    patient = breast_cancer_patients_other_cells@meta.data$Patient.ID,
    # Color palettes
    col = list(cluster = cell_type_colors, patient = palette_patients),
    show_legend = c(FALSE, TRUE),
    gap = unit(1, &quot;mm&quot;),
    simple_anno_size = unit(2, &quot;mm&quot;),
    annotation_name_gp = gpar(fontsize = 6)
  ),
  # Color scale for expression
  col = palette_expression_level,
  # Otherwise you get random vertical white lines where there should not be any
  use_raster = FALSE
)
# Put the legends on the right in a single column
draw(ht, merge_legend = TRUE)
</code></pre>
<p><a href="https://i.sstatic.net/KB0eUrGy.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/KB0eUrGy.png" alt="Heatmap generated with the R package ComplexHeatmap" /></a></p>
<p>Thank you!</p>

CC BY-SA 4.0
2024-12-16T17:52:27.423Z
Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer).
Community
CC BY-SA 4.0
2024-12-17T05:22:44.187Z
Thanks for this; are you able to explain what you did, or provide some of the code that generated this image?
gringer
CC BY-SA 4.0
2024-12-18T01:36:37.407Z
I added the code now, it has a few comments which I think should be sufficient to clarify what I did. Let me know if you think something needs an explanation :)
Alberto Fabbri
CC BY-SA 4.0
2024-12-18T02:07:11.843Z
Fabulous @AlbertoFabbri huge thanks. I do recommend the OP is upvoted for reporting back to the site. Much appreciated.
M__
CC BY-SA 4.0
2024-12-16T16:57:41.737Z
2024-12-18T01:33:40.903Z
2024-12-18T01:33:40.903Z
Alberto Fabbri
<p>Regarding the data range, you should be able to take the scaled data directly from the Seurat object, without having to do any additional scaling:</p>
<pre><code> expr_matrix &lt;- as.matrix(
  GetAssayData(
    slot = &quot;scale.data&quot;, # &lt;--
    breast_cancer_patients_other_cells, 
    layer = &quot;data&quot;, 
    assay = &quot;SCT&quot;)[
    most_significant_other_cells_markers$gene, 
    ]
  )
</code></pre>
<p>FWIW, you can look at the <code>DoHeatmap</code> code by typing the function name without brackets into the R console. This may help in understanding how data points are coloured and scaled:</p>
<pre><code>&gt; DoHeatmap
function (object, features = NULL, cells = NULL, group.by = &quot;ident&quot;, 
    group.bar = TRUE, group.colors = NULL, disp.min = -2.5, disp.max = NULL, 
    slot = &quot;scale.data&quot;, assay = NULL, label = TRUE, size = 5.5, 
    hjust = 0, vjust = 0, angle = 45, raster = TRUE, draw.lines = TRUE, 
    lines.width = NULL, group.bar.height = 0.02, combine = TRUE) 
{
    assay &lt;- assay %||% DefaultAssay(object = object)
    DefaultAssay(object = object) &lt;- assay
    cells &lt;- cells %||% colnames(x = object[[assay]])
...
        }
        plot &lt;- plot + theme(line = element_blank())
        plots[[i]] &lt;- plot
    }
    if (combine) {
        plots &lt;- wrap_plots(plots)
    }
    return(plots)
}
</code></pre>

CC BY-SA 4.0
2024-12-12T07:22:09.280Z
2024-12-12T07:31:13.430Z
2024-12-12T07:31:13.430Z
gringer
<p>HHMmmmm I'll give this a shot as I'm brushing up my R and I do need to  answer questions once in a while. Note, there are stronger R codes on this site than I.
Try the following code:</p>
<pre><code># Extract the expression data for the selected genes
valid_genes &lt;- intersect(rownames(GetAssayData(breast_cancer_patients_other_cells, assay = &quot;SCT&quot;)), 
                         most_significant_other_cells_markers$gene)
expr_matrix &lt;- as.matrix(
  GetAssayData(
    breast_cancer_patients_other_cells, 
    layer = &quot;scale.data&quot;, 
    assay = &quot;SCT&quot;)[valid_genes, ]
)

# Scale the rows
zero_var_rows &lt;- apply(expr_matrix, 1, var) == 0
expr_matrix_scaled &lt;- expr_matrix
expr_matrix_scaled[!zero_var_rows, ] &lt;- t(scale(t(expr_matrix[!zero_var_rows, ])))
expr_matrix_scaled[zero_var_rows, ] &lt;- 0

# Prepare cell type annotations
cell_types &lt;- if (is.null(Idents(breast_cancer_patients_other_cells))) {
  breast_cancer_patients_other_cells@meta.data$cell_type_column
} else {
  Idents(breast_cancer_patients_other_cells)
}

# Create color palette for cell types
unique_cell_types &lt;- unique(cell_types)
cell_type_colors &lt;- setNames(rainbow(length(unique_cell_types)), unique_cell_types)

# Define palette for expression level
valid_values &lt;- expr_matrix_scaled[!is.na(expr_matrix_scaled) &amp; !is.infinite(expr_matrix_scaled)]
palette_expression_level &lt;- colorRamp2(
  c(min(valid_values), median(valid_values), max(valid_values)),
  c(&quot;#FF00FF&quot;, &quot;#000000&quot;, &quot;#FFFF00&quot;)
)

# Define palette for patients
palette_patients &lt;- setNames(rainbow(length(unique(breast_cancer_patients_other_cells@meta.data<span class="math-container">$Patient.ID))),
                         unique(breast_cancer_patients_other_cells@meta.data$</span>Patient.ID))

# Save png
png(here(&quot;test.png&quot;), width = 15, height = 20, units = &quot;cm&quot;, res = 1000)

# Create the heatmap with ComplexHeatmap
Heatmap(
  expr_matrix_scaled,
  name = &quot;Expression&quot;,
  column_split = factor(cell_types),
  cluster_rows = TRUE,
  cluster_columns = TRUE,
  column_title_rot = 0,
  show_column_names = FALSE,
  show_column_dend = FALSE,
  show_row_names = TRUE,
  show_row_dend = FALSE,
  cluster_column_slices = TRUE,
  column_gap = unit(0.5, &quot;mm&quot;),
  row_names_gp = gpar(fontsize = 5),
  column_title = &quot;Top 10 Differentially Expressed Genes per Cluster&quot;,
  top_annotation = HeatmapAnnotation(
    Cluster = cell_types,
    Patient = breast_cancer_patients_other_cells@meta.data$Patient.ID,
    col = list(Cluster = cell_type_colors, Patient = palette_patients),
    show_legend = TRUE,
    gap = unit(1, &quot;mm&quot;),
    simple_anno_size = unit(2, &quot;mm&quot;),
    annotation_name_gp = gpar(fontsize = 6)
  ),
  col = palette_expression_level
)

# Save image
dev.off()
</code></pre>
<p>Potential issues:</p>
<ul>
<li>Does <code>layer = &quot;data&quot;</code> argument in GetAssayData exist or is it incorrect for the assay SCT? By default, Seurat uses layers like &quot;counts&quot;, &quot;data&quot;, or &quot;scale.data&quot;.</li>
<li><code>most_significant_other_cells_markers$gene</code> might contain genes not present in the dataset?</li>
<li>The <code>scale()</code> function may encounter rows with constant values (zero variance), that gives NaN values after scaling.</li>
<li><code>Idents</code> might not have been set correctly for the Seurat object. If Idents returns NULL, this step will fail.</li>
</ul>
<p>Plus lots more</p>
<hr />
<p>What I do recommend is debugging:</p>
<pre><code>print(dim(expr_matrix_scaled))
print(head(cell_types))
print(unique(cell_types))
</code></pre>
<p>This is what an R-coding expert would almost certainly request unless they've encountered exactly the same situation.</p>

CC BY-SA 4.0
2024-12-11T15:57:17.257Z
Your code works but it gives a Heatmap quite similar to the one I posted here. The SCT assay has all three layers, the count layer should contain adjusted counts. All the markers should be in the expression matrix as the find markers function has been run on the same assay. Idents is set properly as it is also needed to generate the heatmap with the Seurat function DoHeatmap. I did not know about the problem with the variance, interesting!
Alberto Fabbri
CC BY-SA 4.0
2024-12-11T20:54:51.680Z
Okay thanks. Well I tried a collection of stuff - but I'm no expert. 
If this was Python I could nail it.
M__
CC BY-SA 4.0
2024-12-11T15:25:11.563Z
2024-12-11T15:51:59.337Z
2024-12-11T15:51:59.337Z
M__
<p>I generated a heatmap using the <code>DoHeatmap</code> function in the Seurat package. The heatmap looks fine but I want to add a second annotation bar on top with the patient data. <a href="https://github.com/satijalab/seurat/issues/2201" rel="nofollow noreferrer">According to this Seurat GitHub issue</a> it is not possible therefore, I decided to recreate an identical heatmap from scratch using ComplexHeatmap. This has proven more challenging than I thought and I would like some help.</p>
<h3>Find markers</h3>
<pre><code># Find all markers of the other clusters
other_cells_markers_data &lt;- FindAllMarkers(
  breast_cancer_patients_other_cells,
  test.use = &quot;wilcox&quot;,
  assay = &quot;SCT&quot;,
  only.pos = FALSE,
  random.seed = 5)

most_significant_other_cells_markers &lt;- other_cells_markers_data %&gt;%
  group_by(cluster) %&gt;%
  dplyr::filter(avg_log2FC &gt; 1 &amp; p_val_adj &lt; 0.05) %&gt;%
  slice_head(n = 10) %&gt;%
  ungroup()
</code></pre>
<h3>Seurat Heatmap</h3>
<pre><code>DoHeatmap(
    breast_cancer_patients_other_cells,
    features = most_significant_other_cells_markers$gene,
    assay = &quot;SCT&quot;,
    label = TRUE,
    size = 2
   ) + theme(
     axis.text.y = element_text(size = 5),
   ) + labs(
     title = paste(&quot;Other cells clusters&quot;),
     subtitle = &quot;Top 10 Differentially Expressed Genes per Cluster&quot;
   )
</code></pre>
<p><a href="https://i.sstatic.net/kDvjxKb8.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/kDvjxKb8.png" alt="enter image description here" /></a></p>
<h3>ComplexHeatmap</h3>
<pre><code># Extract the expression data for the selected genes
expr_matrix &lt;- as.matrix(
  GetAssayData(
    breast_cancer_patients_other_cells, 
    layer = &quot;data&quot;, 
    assay = &quot;SCT&quot;)[
    most_significant_other_cells_markers$gene, 
    ]
  )
## scale the rows
expr_matrix_scaled&lt;- t(scale(t(expr_matrix)))

# Prepare cell type annotations
cell_types &lt;- Idents(breast_cancer_patients_other_cells)

# Create color palette for cell types
unique_cell_types &lt;- unique(cell_types)
cell_type_colors &lt;- setNames(
  rainbow(length(unique_cell_types)),
  unique_cell_types
)

# Recreate the Seurat expression scale
palette_expression_level = colorRamp2(
  c(min(expr_matrix_scaled), median(expr_matrix_scaled), max(expr_matrix_scaled)),
  c(&quot;#FF00FF&quot;, &quot;#000000&quot;, &quot;#FFFF00&quot;))

# Save png
png(here(&quot;test.png&quot;),width=15,height=20,units=&quot;cm&quot;,res=1000)

# Create the heatmap with ComplexHeatmap
Heatmap(
  matrix = expr_matrix_scaled,
  name = &quot;Expression&quot;,
  column_split = factor(cell_types),
  cluster_rows = TRUE,
  cluster_columns = TRUE,
  column_title_rot = 0,
  show_column_names = FALSE,
  show_column_dend = FALSE,
  show_row_names = TRUE,
  show_row_dend = FALSE,
  cluster_column_slices = TRUE,
  column_gap = unit(0.5, &quot;mm&quot;),
  row_names_gp = gpar(fontsize = 5),
  column_title = &quot;Top 10 Differentially Expressed Genes per Cluster&quot;,
  top_annotation = HeatmapAnnotation(
    Cluster = cell_types,
    Patient = breast_cancer_patients_other_cells@meta.data$Patient.ID,
    col = list(Cluster = cell_type_colors, Patient = palette_patients),
    show_legend = TRUE,
    gap = unit(1, &quot;mm&quot;),
    simple_anno_size = unit(2, &quot;mm&quot;),
    annotation_name_gp = gpar(fontsize = 6)
  ),
  # Color scale for expression
  col = palette_expression_level
)

# Save image
dev.off()
</code></pre>
<p><a href="https://i.sstatic.net/f5uNCVD6.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/f5uNCVD6.png" alt="enter image description here" /></a></p>
<p>What parameters am I missing?</p>
<h2>EDIT: Debugging info</h2>
<pre class="lang-r prettyprint-override"><code>&gt; print(dim(expr_matrix_scaled))
[1]    92 30702
&gt; print(head(cell_types))
 5_171 27_171 28_171 29_171 31_171 34_171 
     7      7      7      7      7      7 
Levels: 0 1 2 3 4 5 6 7 8 9
&gt; print(unique(cell_types))
 [1] 7 0 2 9 8 1 4 5 3 6
Levels: 0 1 2 3 4 5 6 7 8 9
</code></pre>

<r><seurat><complexheatmap>
Reproduce Seurat Heatmap with ComplexHeatmap
# Reproduce Seurat Heatmap with ComplexHeatmap

(Asked by: username_0 on 2024-12-11)

I generated a heatmap using the DoHeatmap function in the Seurat package. The heatmap looks fine but I want to add a second annotation bar on top with the patient data. According to this Seurat GitHub issue it is not possible therefore, I decided to recreate an identical heatmap from scratch using ComplexHeatmap. This has proven more challenging than I thought and I would like some help.
Find markers
# Find all markers of the other clusters
other_cells_markers_data <- FindAllMarkers(
  breast_cancer_patients_other_cells,
  test.use = "wilcox",
  assay = "SCT",
  only.pos = FALSE,
  random.seed = 5)

most_significant_other_cells_markers <- other_cells_markers_data %>%
  group_by(cluster) %>%
  dplyr::filter(avg_log2FC > 1 & p_val_adj < 0.05) %>%
  slice_head(n = 10) %>%
  ungroup()

Seurat Heatmap
DoHeatmap(
    breast_cancer_patients_other_cells,
    features = most_significant_other_cells_markers$gene,
    assay = "SCT",
    label = TRUE,
    size = 2
   ) + theme(
     axis.text.y = element_text(size = 5),
   ) + labs(
     title = paste("Other cells clusters"),
     subtitle = "Top 10 Differentially Expressed Genes per Cluster"
   )


ComplexHeatmap
# Extract the expression data for the selected genes
expr_matrix <- as.matrix(
  GetAssayData(
    breast_cancer_patients_other_cells, 
    layer = "data", 
    assay = "SCT")[
    most_significant_other_cells_markers$gene, 
    ]
  )
## scale the rows
expr_matrix_scaled<- t(scale(t(expr_matrix)))

# Prepare cell type annotations
cell_types <- Idents(breast_cancer_patients_other_cells)

# Create color palette for cell types
unique_cell_types <- unique(cell_types)
cell_type_colors <- setNames(
  rainbow(length(unique_cell_types)),
  unique_cell_types
)

# Recreate the Seurat expression scale
palette_expression_level = colorRamp2(
  c(min(expr_matrix_scaled), median(expr_matrix_scaled), max(expr_matrix_scaled)),
  c("#FF00FF", "#000000", "#FFFF00"))

# Save png
png(here("test.png"),width=15,height=20,units="cm",res=1000)

# Create the heatmap with ComplexHeatmap
Heatmap(
  matrix = expr_matrix_scaled,
  name = "Expression",
  column_split = factor(cell_types),
  cluster_rows = TRUE,
  cluster_columns = TRUE,
  column_title_rot = 0,
  show_column_names = FALSE,
  show_column_dend = FALSE,
  show_row_names = TRUE,
  show_row_dend = FALSE,
  cluster_column_slices = TRUE,
  column_gap = unit(0.5, "mm"),
  row_names_gp = gpar(fontsize = 5),
  column_title = "Top 10 Differentially Expressed Genes per Cluster",
  top_annotation = HeatmapAnnotation(
    Cluster = cell_types,
    Patient = breast_cancer_patients_other_cells@meta.data$Patient.ID,
    col = list(Cluster = cell_type_colors, Patient = palette_patients),
    show_legend = TRUE,
    gap = unit(1, "mm"),
    simple_anno_size = unit(2, "mm"),
    annotation_name_gp = gpar(fontsize = 6)
  ),
  # Color scale for expression
  col = palette_expression_level
)

# Save image
dev.off()


What parameters am I missing?
EDIT: Debugging info
> print(dim(expr_matrix_scaled))
[1]    92 30702
> print(head(cell_types))
 5_171 27_171 28_171 29_171 31_171 34_171 
     7      7      7      7      7      7 
Levels: 0 1 2 3 4 5 6 7 8 9
> print(unique(cell_types))
 [1] 7 0 2 9 8 1 4 5 3 6
Levels: 0 1 2 3 4 5 6 7 8 9

**Tags:** r, seurat, complexheatmap

---

## 3 answers

### Answer by username_0 on 2024-12-16. Score: 1 | Accepted answer

After a lot of experimentation with the various parameters I was able to get a heatmap that is rather close to the one generated by Seurat!
# Unique is used to eliminate duplicated genes,
# this is done automatically by Seurat DoHeatmap
features <- unique(most_significant_other_cells_markers$gene)

# Extract the expression data for the selected genes from the scaled layer
expr_matrix <- as.matrix(
  GetAssayData(
    breast_cancer_patients_other_cells, 
    layer = "scale.data", 
    assay = "SCT"
  )[
    features,
  ]
)

# Prepare cell type annotations
cell_types <- Idents(breast_cancer_patients_other_cells)
# Create vector with unique and sorted cell types
unique_cell_types <- sort(unique(cell_types))

# Create color palette for cell types
cell_type_colors <- setNames(
  gg_color_hue(length(unique_cell_types)),
  unique_cell_types
)

# Recreate the Seurat expression scale
palette_expression_level = circlize::colorRamp2(
  c(min(expr_matrix), median(expr_matrix), min(2.5, max(expr_matrix))),
  c("#FF00FF", "#000000", "#FFFF00"))

# Create the heatmap with ComplexHeatmap
ht = Heatmap(
  matrix = expr_matrix,
  row_order = features,
  name = "expression",
  column_split = factor(cell_types, levels = unique_cell_types),
  # Do not cluster rows or columns otherwise row_order/column_order are ignored
  cluster_rows = FALSE,
  cluster_columns = FALSE,
  column_title_rot = 0,
  show_column_names = FALSE,
  show_column_dend = FALSE,
  show_row_names = TRUE,
  show_row_dend = FALSE,
  cluster_column_slices = TRUE,
  column_gap = unit(0.5, "mm"),
  row_names_gp = gpar(fontsize = 5),
  # The column title can be either a title for all the columns
  # or a vector with a name for every column
  column_title = unique_cell_types,
  column_title_gp = gpar(fontsize = 7),
  # Add the annotation bars on top
  top_annotation = HeatmapAnnotation(
    # Give a name to the annotation, not used on the actual plot
    name = "Clusters",
    # Annotate the columns
    which = "column",
    # First annotation - clusters
    cluster = cell_types,
    # Second annotation - patients
    patient = breast_cancer_patients_other_cells@meta.data$Patient.ID,
    # Color palettes
    col = list(cluster = cell_type_colors, patient = palette_patients),
    show_legend = c(FALSE, TRUE),
    gap = unit(1, "mm"),
    simple_anno_size = unit(2, "mm"),
    annotation_name_gp = gpar(fontsize = 6)
  ),
  # Color scale for expression
  col = palette_expression_level,
  # Otherwise you get random vertical white lines where there should not be any
  use_raster = FALSE
)
# Put the legends on the right in a single column
draw(ht, merge_legend = TRUE)


Thank you!

> **Comments:**
> **username_1**: Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer).  
> **username_2**: Thanks for this; are you able to explain what you did, or provide some of the code that generated this image?  
> **username_0**: I added the code now, it has a few comments which I think should be sufficient to clarify what I did. Let me know if you think something needs an explanation :)  
> **username_3**: Fabulous @AlbertoFabbri huge thanks. I do recommend the OP is upvoted for reporting back to the site. Much appreciated.  

---

### Answer by username_2 on 2024-12-12. Score: 1

Regarding the data range, you should be able to take the scaled data directly from the Seurat object, without having to do any additional scaling:
 expr_matrix <- as.matrix(
  GetAssayData(
    slot = "scale.data", # <--
    breast_cancer_patients_other_cells, 
    layer = "data", 
    assay = "SCT")[
    most_significant_other_cells_markers$gene, 
    ]
  )

FWIW, you can look at the DoHeatmap code by typing the function name without brackets into the R console. This may help in understanding how data points are coloured and scaled:
> DoHeatmap
function (object, features = NULL, cells = NULL, group.by = "ident", 
    group.bar = TRUE, group.colors = NULL, disp.min = -2.5, disp.max = NULL, 
    slot = "scale.data", assay = NULL, label = TRUE, size = 5.5, 
    hjust = 0, vjust = 0, angle = 45, raster = TRUE, draw.lines = TRUE, 
    lines.width = NULL, group.bar.height = 0.02, combine = TRUE) 
{
    assay <- assay %||% DefaultAssay(object = object)
    DefaultAssay(object = object) <- assay
    cells <- cells %||% colnames(x = object[[assay]])
...
        }
        plot <- plot + theme(line = element_blank())
        plots[[i]] <- plot
    }
    if (combine) {
        plots <- wrap_plots(plots)
    }
    return(plots)
}


---

### Answer by username_3 on 2024-12-11. Score: 0

HHMmmmm I'll give this a shot as I'm brushing up my R and I do need to  answer questions once in a while. Note, there are stronger R codes on this site than I.
Try the following code:
# Extract the expression data for the selected genes
valid_genes <- intersect(rownames(GetAssayData(breast_cancer_patients_other_cells, assay = "SCT")), 
                         most_significant_other_cells_markers$gene)
expr_matrix <- as.matrix(
  GetAssayData(
    breast_cancer_patients_other_cells, 
    layer = "scale.data", 
    assay = "SCT")[valid_genes, ]
)

# Scale the rows
zero_var_rows <- apply(expr_matrix, 1, var) == 0
expr_matrix_scaled <- expr_matrix
expr_matrix_scaled[!zero_var_rows, ] <- t(scale(t(expr_matrix[!zero_var_rows, ])))
expr_matrix_scaled[zero_var_rows, ] <- 0

# Prepare cell type annotations
cell_types <- if (is.null(Idents(breast_cancer_patients_other_cells))) {
  breast_cancer_patients_other_cells@meta.data$cell_type_column
} else {
  Idents(breast_cancer_patients_other_cells)
}

# Create color palette for cell types
unique_cell_types <- unique(cell_types)
cell_type_colors <- setNames(rainbow(length(unique_cell_types)), unique_cell_types)

# Define palette for expression level
valid_values <- expr_matrix_scaled[!is.na(expr_matrix_scaled) & !is.infinite(expr_matrix_scaled)]
palette_expression_level <- colorRamp2(
  c(min(valid_values), median(valid_values), max(valid_values)),
  c("#FF00FF", "#000000", "#FFFF00")
)

# Define palette for patients
palette_patients <- setNames(rainbow(length(unique(breast_cancer_patients_other_cells@meta.data$Patient.ID))),
                         unique(breast_cancer_patients_other_cells@meta.data$Patient.ID))

# Save png
png(here("test.png"), width = 15, height = 20, units = "cm", res = 1000)

# Create the heatmap with ComplexHeatmap
Heatmap(
  expr_matrix_scaled,
  name = "Expression",
  column_split = factor(cell_types),
  cluster_rows = TRUE,
  cluster_columns = TRUE,
  column_title_rot = 0,
  show_column_names = FALSE,
  show_column_dend = FALSE,
  show_row_names = TRUE,
  show_row_dend = FALSE,
  cluster_column_slices = TRUE,
  column_gap = unit(0.5, "mm"),
  row_names_gp = gpar(fontsize = 5),
  column_title = "Top 10 Differentially Expressed Genes per Cluster",
  top_annotation = HeatmapAnnotation(
    Cluster = cell_types,
    Patient = breast_cancer_patients_other_cells@meta.data$Patient.ID,
    col = list(Cluster = cell_type_colors, Patient = palette_patients),
    show_legend = TRUE,
    gap = unit(1, "mm"),
    simple_anno_size = unit(2, "mm"),
    annotation_name_gp = gpar(fontsize = 6)
  ),
  col = palette_expression_level
)

# Save image
dev.off()

Potential issues:

Does layer = "data" argument in GetAssayData exist or is it incorrect for the assay SCT? By default, Seurat uses layers like "counts", "data", or "scale.data".
most_significant_other_cells_markers$gene might contain genes not present in the dataset?
The scale() function may encounter rows with constant values (zero variance), that gives NaN values after scaling.
Idents might not have been set correctly for the Seurat object. If Idents returns NULL, this step will fail.

Plus lots more

What I do recommend is debugging:
print(dim(expr_matrix_scaled))
print(head(cell_types))
print(unique(cell_types))

This is what an R-coding expert would almost certainly request unless they've encountered exactly the same situation.

> **Comments:**
> **username_0**: Your code works but it gives a Heatmap quite similar to the one I posted here. The SCT assay has all three layers, the count layer should contain adjusted counts. All the markers should be in the expression matrix as the find markers function has been run on the same assay. Idents is set properly as it is also needed to generate the heatmap with the Seurat function DoHeatmap. I did not know about the problem with the variance, interesting!  
> **username_3**: Okay thanks. Well I tried a collection of stuff - but I'm no expert.  If this was Python I could nail it.  

---

