Reputation: 43
I am trying to plot a seaborn heatmap with custom locations and labels on both axes. The dataframe looks like this:
I can plot this normally with seaborn.heatmap
:
fig, ax = plt.subplots(figsize=(8, 8))
sns.heatmap(genome_freq.applymap(lambda x: np.log10(x+1)),
ax=ax)
plt.show()
I have a list of positions I'd like to set as the xticks (binned_chrom_genome_pos
):
[1000000, 248000000, 491000000, 690000000, 881000000, 1062000000, 1233000000, 1392000000, 1538000000, 1679000000, 1814000000, 1948000000, 2081000000, 2195000000, 2301000000, 2402000000, 2490000000, 2569000000, 2645000000, 2709000000, 2772000000, 2819000000, 2868000000, 3023000000]
However, when I try to modify the xticks, the plot becomes empty:
plt.xticks(binned_chrom_genome_pos)
I also noticed that the x-axis labels do not correspond to the ticks specified.
Could someone assist me in plotting this properly?
Upvotes: 1
Views: 6782
Reputation: 9481
ax.get_xticks()
returns the positions of the ticks. You can see that they are between 0.5 and 3000. These values refer to the index of your data. Large values, set by plt.xticks
, or ax.set_xticks
are still interpreted as data indices. So, if you have 10 rows of data, and set xticks
to [0, 1000]
, the data in your figure will only occupy 1% of the x-range, hence disappearing. I am not sure if I am making myself clear, so I will give an example with synthetic data:
import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
#generating data
dic = {a:np.random.randint(0,1000,100) for a in range(0,1000000, 10000)}
genome_freq = pd.DataFrame(dic, index=range(0,1000000, 10000))
#plotting heatmaps
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4))
sns.heatmap(genome_freq.applymap(lambda x: np.log10(x+1)),
ax=ax1)
sns.heatmap(genome_freq.applymap(lambda x: np.log10(x+1)),
ax=ax2)
old_ticks = ax2.get_xticks()
print(np.min(old_ticks), np.max(old_ticks), len(old_ticks)) # prints 0.5 99.5 34
ax2.set_xticks([0,300]) # setting xticks with values way larger than your index squishes your data
plt.show()
So, what you want to do, is to change the xticks based on the size of your data, and then overwrite xticklabels
:
Given the new labels from your question:
new_labels = [1000000, 248000000, 491000000, 690000000, 881000000, 1062000000, 1233000000, 1392000000, 1538000000, 1679000000, 1814000000, 1948000000, 2081000000, 2195000000, 2301000000, 2402000000, 2490000000, 2569000000, 2645000000, 2709000000, 2772000000, 2819000000, 2868000000, 3023000000]
len(new_labels) # returns 24
fig, ax = plt.subplots(figsize=(4, 4))
sns.heatmap(genome_freq.applymap(lambda x: np.log10(x+1)),
ax=ax)
So, now we want 24 evenly spaced xticks between the former minimum and the former maximum. We can use np.linspace
to achieve that:
old_ticks = ax.get_xticks()
new_ticks = np.linspace(np.min(old_ticks), np.max(old_ticks), len(new_labels))
ax.set_xticks(new_ticks)
ax.set_xticklabels(new_labels)
plt.show()
Upvotes: 3