У меня есть файл с разделителями табуляции, содержащий регионы и соответствующие биологические объекты, найденные в этих регионах (я проверил 67, поэтому вы говорите, что каждый регион был проверен на наличие или отсутствие этих 67 объектов и их частоту).
У меня есть все эти данные в табличном формате.
Пример данных приведен ниже
Region ATF3 BCL3 BCLAF1 BDP1 BRF1 BRF2 Brg1 CCNT2 CEBPB CHD2 CTCF CTCFL E2F6 ELF1
chr1:109102470:109102970 0 0 1 0 0 0 0 1 0 0 4 1 4 1
chr1:110526886:110527386 0 0 0 0 0 0 0 1 1 0 4 1 0 1
chr1:115300671:115301171 0 0 1 0 0 0 0 0 1 1 4 1 1 1
chr1:115323308:115323808 0 0 0 0 0 0 0 1 0 0 2 1 1 0
chr1:11795641:11796141 1 0 0 0 0 0 0 1 2 0 0 0 1 0
chr1:118148103:118148603 0 0 0 0 0 0 0 1 0 0 0 0 0 1
chr1:150521397:150521897 0 0 0 0 0 0 0 2 2 0 6 2 4 0
chr1:150601609:150602109 0 0 0 0 0 0 0 0 3 2 0 0 1 0
chr1:150602098:150602598 0 0 0 0 0 0 0 0 1 1 0 0 0 0
chr1:151119140:151119640 0 0 0 0 0 0 0 1 0 0 0 0 1 0
chr1:151128604:151129104 0 0 0 0 0 0 0 0 0 0 3 0 0 0
chr1:153517729:153518229 0 0 0 0 0 0 0 0 0 0 0 0 0 0
chr1:153962738:153963238 0 0 0 0 0 0 0 1 1 0 0 0 0 1
chr1:154155682:154156182 0 0 0 0 0 0 0 1 0 0 0 0 1 1
chr1:154155725:154156225 0 0 0 0 0 0 0 1 0 0 0 0 1 1
chr1:154192154:154192654 0 0 0 0 0 0 0 0 0 0 0 0 0 0
chr1:154192824:154193324 1 0 0 0 0 0 0 1 0 1 0 0 1 1
chr1:154192943:154193443 1 0 0 0 0 0 0 1 0 2 0 0 1 1
chr1:154193273:154193773 1 0 0 0 0 0 0 1 0 2 0 0 2 1
chr1:154193313:154193813 0 0 0 0 0 0 0 1 0 2 0 0 2 1
chr1:155904188:155904688 0 0 0 0 0 0 0 1 0 0 0 0 1 1
chr1:155947966:155948466 0 0 0 0 0 0 0 1 0 0 3 0 0 1
chr1:155948336:155948836 0 0 0 0 0 0 0 1 0 0 5 1 0 1
chr1:156023516:156024016 0 0 0 0 0 0 0 1 0 1 4 1 1 1
chr1:156024016:156024516 0 1 1 0 0 0 0 0 0 2 0 0 1 1
chr1:156163229:156163729 0 0 0 0 0 0 0 0 0 0 2 0 0 1
chr1:160990902:160991402 0 0 0 0 0 0 0 0 0 1 0 0 1 2
chr1:160991133:160991633 0 0 0 0 0 0 0 0 0 1 0 0 1 2
chr1:161474704:161475204 0 0 0 0 0 0 0 0 0 0 0 0 0 0
chr1:161509530:161510030 0 0 1 1 1 0 0 0 1 0 1 0 0 1
chr1:161590964:161591464 0 0 0 1 1 0 0 0 0 0 0 0 0 0
chr1:169075446:169075946 0 0 0 0 0 0 0 2 0 0 4 0 3 0
chr1:17053279:17053779 0 0 0 1 0 0 0 0 0 1 0 0 0 0
chr1:1709909:1710409 0 0 0 0 0 0 0 2 0 1 0 0 3 1
chr1:1710297:1710797 0 0 0 0 0 0 0 0 0 1 6 0 1 1
Теперь, как я могу поместить это в тепловую карту от цветового кода от светло-красного до темно-красного (в зависимости от частоты и белого в случае отсутствия)?
Есть ли другой лучший способ представить этот тип данных?
Ответ 1 · рейтинг 4 · Thorsten Kranz
Используйте Matplotlib
import pylab as plt
import numpy as np
data = np.loadtxt("14318737.txt", skiprows=1, converters={0:lambda x: 0})
plot_data = np.ma.masked_equal(data[:,1:], 0)
plt.imshow(plot_data, cmap=plt.cm.get_cmap("Reds"), interpolation="nearest")
plt.colorbar()
plt.show()
Я игнорирую первую строку и первый столбец (если они вам нужны для меток, нам нужно изменить это). Для остальных данных все нулевые значения маскируются (поэтому они отображаются белым цветом на графике), а затем эти данные отображаются в виде графика с цветовой кодировкой.
imshow имеет множество других параметров для управления результатом, например. происхождение (нижнее/верхнее), аспект (авто/равно/некоторое_отношение).
Вы пишете о регионах - вы имеете в виду географические районы? Тогда вам может понадобиться Basemap Toolkit для Matplotlib для создания карт с цветовой кодировкой.
Изменить
Новые требования, новый пример
import pylab as plt
import numpy as np
fn = "14318737.txt"
with open(fn, "r") as f:
labels = f.readline().rstrip("\n").split()[1:]
data = np.loadtxt(fn, skiprows=1, converters={0:lambda x: 0})
plot_data = np.ma.masked_equal(data[:,1:], 0)
plt.subplots_adjust(left=0.1, bottom=0.15, right=0.99, top=0.95)
plt.imshow(plot_data, cmap=plt.cm.get_cmap("Reds"), interpolation="nearest", aspect = "auto")
plt.xticks(range(len(labels)), labels, rotation=90, va="top", ha="center")
plt.colorbar()
plt.show()
Теперь я сначала читаю этикетки с первой строки. Я добавил аргумент ключевого слова aspect в вызов imshow. Я создаю ярлыки для каждого фактора.
Кроме того, я корректирую расположение графиков с помощью subplots_adjust. Вы можете играть с этими параметрами, пока они не будут соответствовать вашим потребностям.
Теперь результат такой:
Если вам нужны другие отметки для оси Y, используйте plt.yticks, это как xticks в моем примере.
Ответ 2 · рейтинг 1 · Thorsten Kranz
Из-за комментариев к моему другому ответу у OP возник еще один вопрос о поиске 2d-кластеров. Вот некоторый ответ.
Взято из моей библиотеки eegpy, я использую метод найти_кластеры. Он выполняет обход 2d-массива, находя все кластеры выше/ниже заданного порога.
Вот мой код:
import pylab as plt
import numpy as np
from Queue import Queue
def find_clusters(ar,thres,cmp_type="greater"):
"""For a given 2d-array (test statistic), find all clusters which
are above/below a certain threshold.
"""
if not cmp_type in ["lower","greater","abs_greater"]:
raise ValueError("cmp_type must be in [\"lower\",\"greater\",\"abs_greater\"]")
clusters = []
if cmp_type=="lower":
ar_in = (ar<thres).astype(np.bool)
elif cmp_type=="greater":
ar_in = (ar>thres).astype(np.bool)
else: #cmp_type=="abs_greater":
ar_in = (abs(ar)>thres).astype(np.bool)
already_visited = np.zeros(ar_in.shape,np.bool)
for i_s in range(ar_in.shape[0]): #i_s wie i_sample
for i_f in range(ar_in.shape[1]):
if not already_visited[i_s,i_f]:
if ar_in[i_s,i_f]:
#print "Anzahl cluster:", len(clusters)
mask = np.zeros(ar_in.shape,np.bool)
check_queue = Queue()
check_queue.put((i_s,i_f))
while not check_queue.empty():
pos_x,pos_y = check_queue.get()
if not already_visited[pos_x,pos_y]:
#print pos_x,pos_y
already_visited[pos_x,pos_y] = True
if ar_in[pos_x,pos_y]:
mask[pos_x,pos_y] = True
for coords in [(pos_x-1,pos_y),(pos_x+1,pos_y),(pos_x,pos_y-1),(pos_x,pos_y+1)]: #Direct Neighbors
if 0<=coords[0]<ar_in.shape[0] and 0<=coords[1]<ar_in.shape[1]:
check_queue.put(coords)
clusters.append(mask)
return clusters
fn = "14318737.txt"
with open(fn, "r") as f:
labels = f.readline().rstrip("\n").split()[1:]
data = np.loadtxt(fn, skiprows=1, converters={0:lambda x: 0})
clusters = find_clusters(data, 0, "greater")
plot_data = np.ma.masked_equal(data[:,1:], 0)
plt.subplots_adjust(left=0.1, bottom=0.15, right=0.99, top=0.95)
plt.imshow(plot_data, cmap=plt.cm.get_cmap("Reds"), interpolation="nearest", aspect = "auto",
vmin=0, extent=[0.5,plot_data.shape[1]+0.5, plot_data.shape[0] - 0.5, -0.5])
plt.colorbar()
for cl in clusters:
plt.contour(cl.astype(np.int),[0.5], colors="k", lw=2)
plt.xticks(np.arange(1, len(labels)+2), labels, rotation=90, va="top", ha="center")
plt.show()
что дает изображение вида:
clusters - это список булевых 2d-массивов (True/False). Каждый массив представляет один кластер, где каждое логическое значение указывает, является ли конкретная "точка" частью этого кластера. Вы можете использовать его в любом дальнейшем анализе.
ИЗМЕНИТЬ
Теперь немного веселья на кластерах
import pylab as plt
import numpy as np
from Queue import Queue
def find_clusters(ar,thres,cmp_type="greater"):
"""For a given 2d-array (test statistic), find all clusters which
are above/below a certain threshold.
"""
if not cmp_type in ["lower","greater","abs_greater"]:
raise ValueError("cmp_type must be in [\"lower\",\"greater\",\"abs_greater\"]")
clusters = []
if cmp_type=="lower":
ar_in = (ar<thres).astype(np.bool)
elif cmp_type=="greater":
ar_in = (ar>thres).astype(np.bool)
else: #cmp_type=="abs_greater":
ar_in = (abs(ar)>thres).astype(np.bool)
already_visited = np.zeros(ar_in.shape,np.bool)
for i_s in range(ar_in.shape[0]): #i_s wie i_sample
for i_f in range(ar_in.shape[1]):
if not already_visited[i_s,i_f]:
if ar_in[i_s,i_f]:
#print "Anzahl cluster:", len(clusters)
mask = np.zeros(ar_in.shape,np.bool)
check_queue = Queue()
check_queue.put((i_s,i_f))
while not check_queue.empty():
pos_x,pos_y = check_queue.get()
if not already_visited[pos_x,pos_y]:
#print pos_x,pos_y
already_visited[pos_x,pos_y] = True
if ar_in[pos_x,pos_y]:
mask[pos_x,pos_y] = True
for coords in [(pos_x-1,pos_y),(pos_x+1,pos_y),(pos_x,pos_y-1),(pos_x,pos_y+1)]: #Direct Neighbors
if 0<=coords[0]<ar_in.shape[0] and 0<=coords[1]<ar_in.shape[1]:
check_queue.put(coords)
clusters.append(mask)
return clusters
fn = "14318737.txt"
data = []
with open(fn, "r") as f:
labels = f.readline().rstrip("\n").split()[1:]
for line in f:
data.append([int(v) for v in line.split()[1:]])
data = np.array(data) #np.loadtxt(fn, skiprows=1, usecols=range(1,15))#converters={0:lambda x: 0})
clusters = find_clusters(data, 0, "greater")
large_clusters = filter(lambda cl: cl.sum()>5, clusters) #Only take clusters with five or more items
large_clusters = sorted(large_clusters, key=lambda cl: -cl.sum())
plot_data = np.ma.masked_equal(data[:,:], 0)
plt.subplots_adjust(left=0.1, bottom=0.15, right=0.99, top=0.95)
plt.imshow(plot_data, cmap=plt.cm.get_cmap("Reds"), interpolation="nearest", aspect = "auto",
vmin=0, extent=[-0.5,plot_data.shape[1]-0.5, plot_data.shape[0] - 0.5, -0.5])
plt.colorbar()
for cl in large_clusters:
plt.contour(cl.astype(np.int),[.5], colors="k", lw=2)
plt.xticks(np.arange(0, len(labels)+1), labels, rotation=90, va="top", ha="center")
print "Summary of all large clusters:\n"
print "#\tSize\tIn regions"
for i, cl in enumerate(large_clusters):
print "%i\t%i\t" % (i, cl.sum()),
regions_in_cluster = np.where(np.any(cl, axis=0))[0]
min_region = labels[min(regions_in_cluster)]
max_region = labels[max(regions_in_cluster)]
print "%s to %s" % (min_region, max_region)
plt.xlim(-0.5,plot_data.shape[1]-0.5)
plt.show()
Я фильтрую все кластеры, в которые включено более пяти точек. Я рисую только эти. В качестве альтернативы вы можете использовать сумму data внутри каждого кластера. Затем я сортирую эти большие кластеры по размеру в порядке убывания.
Наконец, я печатаю сводку по всем большим кластерам, включая имена всех кластеров, через которые они проходят.