Тепловая карта огромного набора данных

У меня есть файл с разделителями табуляции, содержащий регионы и соответствующие биологические объекты, найденные в этих регионах (я проверил 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

Теперь, как я могу поместить это в тепловую карту от цветового кода от светло-красного до темно-красного (в зависимости от частоты и белого в случае отсутствия)?

Есть ли другой лучший способ представить этот тип данных?


person Angelo    schedule 14.01.2013    source источник
comment
кроме ваших данных, можете ли вы показать что вы пробовали?   -  person Inbar Rose    schedule 14.01.2013
comment
Хм, этот сайт вопросов и ответов для практического программирования. Не думаю, что есть специалисты по инфографике.   -  person Denis    schedule 14.01.2013
comment
Что вы имеете в виду под огромным? Много строк или столбцов? Если одно из этих чисел приближается к количеству пикселей, которое вам нужно для создания графика, это не будет хорошим подходом.   -  person Thorsten Kranz    schedule 14.01.2013
comment
@ThorstenKranz 67 столбцов и 1100 строк   -  person Angelo    schedule 15.01.2013
comment
@Angelo, вам обязательно нужно сохранить свое изображение как большое изображение (используя plt.savefig("output.png") или подобное), чтобы ваши 1100 строк имели смысл.   -  person Thorsten Kranz    schedule 15.01.2013


Ответы (2)


Используйте 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 в моем примере.

person Thorsten Kranz    schedule 14.01.2013
comment
Что-то подобное я и подозревал, так что оно вам не понадобится - person Thorsten Kranz; 14.01.2013
comment
@ Thorsten, Извините за беспокойство, но изображение слишком узкое и я не вижу метки (названия моих факторов, у меня их 67) :( Помогите пожалуйста - person Angelo; 15.01.2013
comment
Я создал второй пример, который должен соответствовать вашим требованиям. - person Thorsten Kranz; 15.01.2013
comment
Торстен Кранц: можно ли сгруппировать результаты? - person Angelo; 07.05.2013
comment
Не могли бы вы объяснить, что вы подразумеваете под кластером, а также результаты. Вы имеете в виду найти кластеры в этом 2d-изображении? Это было бы возможно, но я боюсь, что вы могли бы иметь в виду что-то другое. - person Thorsten Kranz; 07.05.2013
comment
Да, я хотел найти кластеры на этом 2D-изображении, а также начать масштабирование с нуля вместо 1. Не могли бы вы отредактировать сценарий и включить их, поскольку мне не удалось его настроить. Спасибо. - person Angelo; 07.05.2013
comment
вопрос 2 прост - просто используйте дополнительный аргумент ключевого слова в imshow, то есть vmin=0. Вопрос 1 немного сложнее. Как определить кластер? Все связанные значения выше некоторого порога? Какой порог? 0? Я отправлю еще один ответ с некоторым примером кода. - person Thorsten Kranz; 08.05.2013
comment
Кластеры: на основе корреляции или евклидова расстояния что-то в этом роде? - person Angelo; 08.05.2013

Из-за комментариев к моему другому ответу у 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 внутри каждого кластера. Затем я сортирую эти большие кластеры по размеру в порядке убывания.

Наконец, я печатаю сводку по всем большим кластерам, включая имена всех кластеров, через которые они проходят. Только большие кластеры

person Thorsten Kranz    schedule 08.05.2013
comment
Спасибо за обновленный код. Поскольку мои данные относятся к 2700 регионам, возможна ли кластеризация на основе строк. Я получаю очень неприятный образ. - person Angelo; 08.05.2013
comment
Что вы подразумеваете под кластером на основе строк. Мой алгоритм ищет в строках и столбцах. Вы имеете в виду поиск только по строкам? - person Thorsten Kranz; 08.05.2013
comment
хорошо, понял. Могу ли я также получить эти кластеры в какой-то переменной и отобразить их имена, начиная с самого большого кластера (что-то вроде кластера 1 --> E2F6 и ELF1) до самого маленького. - person Angelo; 08.05.2013
comment
Да, вы можете делать с этими кластерами все, что хотите. Я бы рекомендовал отфильтровать все мелкие кластеры (статистические колебания) и т. д. Приведу пример. - person Thorsten Kranz; 08.05.2013