Mam zestaw punktów danych X, Y (około 10k), które są łatwe do wykreślenia jako wykres rozproszenia, ale które chciałbym przedstawić jako mapę termiczną.
Przejrzałem przykłady w MatPlotLib i wszystkie wydają się już zaczynać od wartości komórek heatmap w celu wygenerowania obrazu.
Czy istnieje metoda, która przekształca wiązkę x, y, wszystko inne, w mapę cieplną (gdzie strefy o wyższej częstotliwości x, y byłyby „cieplejsze”)?
python
matplotlib
heatmap
histogram2d
greye
źródło
źródło
Odpowiedzi:
Jeśli nie chcesz sześciokątów, możesz użyć
histogram2d
funkcji numpy :To tworzy mapę cieplną 50x50. Jeśli chcesz, powiedzmy, 512x384, możesz
bins=(512, 384)
zadzwonić dohistogram2d
.Przykład:
źródło
axes
instancję, w której mogę dodać tytuł, etykiety osi itp., A następnie wykonać normalnąsavefig()
czynność, tak jak w przypadku każdego innego typowego wykresu matplotlib.plt.savefig('filename.png')
działa? Jeśli chcesz uzyskać instancję osi, użyj zorientowanego obiektowo interfejsu Matplotlib:fig = plt.figure()
ax = fig.gca()
ax.imshow(...)
fig.savefig(...)
imshow()
ma tę samą kategorię funkcji coscatter()
. Szczerze mówiąc, nie rozumiem, dlaczegoimshow()
przekształca tablicę pływaków 2D w bloki o odpowiednim kolorze, podczas gdy rozumiem, coscatter()
należy zrobić z taką tablicą.plt.imshow(heatmap.T, extent=extent, origin = 'lower')
from matplotlib.colors import LogNorm
plt.imshow(heatmap, norm=LogNorm())
plt.colorbar()
W leksykonie Matplotlib myślę, że chcesz wykresu szesnastkowego .
Jeśli nie znasz tego typu wykresu, jest to tylko dwuwymiarowy histogram, na którym płaszczyzna xy jest mozaikowana regularną siatką sześciokątów.
Tak więc z histogramu można po prostu policzyć liczbę punktów przypadających na każdy sześciokąt, dyskretyzować obszar kreślenia jako zestaw okien , przypisać każdy punkt do jednego z tych okien; na koniec zamapuj okna na tablicę kolorów , a otrzymasz schemat szesnastkowy.
Chociaż rzadziej używane niż np. Koła lub kwadraty, sześciokąty są lepszym wyborem dla geometrii pojemnika binningowego, jest intuicyjne:
sześciokąty mają symetrię najbliższego sąsiada (np. kwadratowe kosze nie, np. odległość od punktu na granicy kwadratu do punktu wewnątrz tego kwadratu nie jest wszędzie równa) i
sześciokąt jest najwyższym n-wielokątem, który zapewnia regularną teselację w płaszczyźnie (tzn. możesz bezpiecznie ponownie modelować podłogę w kuchni za pomocą płytek w kształcie sześciokąta, ponieważ po zakończeniu nie będziesz mieć pustej przestrzeni między płytkami - nie dotyczy to wszystkie inne wyższe-n, n> = 7, wielokąty).
( Matplotlib używa terminu wykres heksbinowy ; podobnie jak (AFAIK) wszystkie biblioteki kreślące dla R ; nadal nie wiem, czy jest to ogólnie przyjęty termin dla wykresów tego typu, chociaż podejrzewam, że jest prawdopodobne, biorąc pod uwagę, że hexbin jest krótki dla binoksu heksagonalnego , który opisuje niezbędny krok w przygotowaniu danych do wyświetlenia.)
źródło
gridsize=
parametr. Chciałbym wybrać taki, aby sześciokąty po prostu stykały się bez nakładania. Zauważyłem,gridsize=100
że wytworzy to mniejsze sześciokąty, ale jak wybrać odpowiednią wartość?Edycja: Dla lepszego przybliżenia odpowiedzi Alejandro, patrz poniżej.
Wiem, że to stare pytanie, ale chciałem dodać coś do odpowiedzi Alejandro: Jeśli chcesz uzyskać ładny wygładzony obraz bez użycia py-sphviewer, możesz zamiast tego użyć
np.histogram2d
i zastosować filtr gaussowski (odscipy.ndimage.filters
) do mapy cieplnej :Produkuje:
Wykres rozproszenia is = 16 wykreślony jeden na drugim dla Agape Gal'lo (kliknij, aby uzyskać lepszy widok):
Jedną różnicę, którą zauważyłem przy moim podejściu z filtrem gaussowskim i podejściu Alejandro, było to, że jego metoda pokazuje struktury lokalne znacznie lepiej niż moja. Dlatego zaimplementowałem prostą metodę najbliższego sąsiada na poziomie pikseli. Ta metoda oblicza dla każdego piksela odwrotną sumę odległości
n
najbliższych punktów w danych. Ta metoda jest dość kosztowna obliczeniowo w wysokiej rozdzielczości i myślę, że jest szybszy sposób, więc daj mi znać, jeśli masz jakieś ulepszenia.Aktualizacja: jak podejrzewałam, metoda Scipy jest znacznie szybsza
scipy.cKDTree
. Zobacz odpowiedź Gabriela na wdrożenie.Tak czy inaczej, oto mój kod:
Wynik:
źródło
myplot
funkcji dodaćrange
parametr donp.histogram2d
:np.histogram2d(x, y, bins=bins, range=[[-5, 5], [-3, 4]])
w pętli for zestaw X i Y lim osi:ax.set_xlim([-5, 5])
ax.set_ylim([-3, 4])
. Dodatkowo domyślnieimshow
utrzymuje współczynnik kształtu identyczny ze współczynnikiem twoich osi (więc w moim przykładzie współczynnik wynosi 10: 7), ale jeśli chcesz, aby pasował do okna wykresu, dodaj parametraspect='auto'
doimshow
.Zamiast używać np.hist2d, który generalnie generuje dość brzydkie histogramy, chciałbym poddać recyklingowi py-sphviewer , pakiet Pythona do renderowania symulacji cząstek przy użyciu adaptacyjnego wygładzania jądra, który można łatwo zainstalować z pip (patrz dokumentacja strony). Rozważ następujący kod oparty na przykładzie:
co daje następujący obraz:
Jak widać, obrazy wyglądają całkiem ładnie, a my jesteśmy w stanie zidentyfikować na nim różne podstruktury. Te obrazy są konstruowane rozkładając podaną wagę dla każdego punktu w określonej dziedzinie, zdefiniowanej przez długość wygładzania, która z kolei wynika z odległości do bliższego sąsiada nb (na przykład wybrałem 16, 32 i 64). Zatem regiony o większej gęstości są zazwyczaj rozłożone na mniejsze regiony w porównaniu do regionów o mniejszej gęstości.
Funkcja myplot jest po prostu bardzo prostą funkcją, którą napisałem, aby przekazać dane x, y py-sphviewerowi, aby wykonał magię.
źródło
Jeśli korzystasz z 1.2.x.
źródło
Seaborn ma teraz funkcję jointplot, która powinna tu dobrze działać:
źródło
fig = plt.figure(figsize=(12, 12))
, a następnie pobierz bieżącą oś za pomocąax=plt.gca()
, a następnie dodaj argumentax=ax
dojointplot
funkcji.a początkowe pytanie brzmiało ... jak przekonwertować wartości rozproszenia na wartości siatki, prawda?
histogram2d
zlicza częstotliwość na komórkę, jednak jeśli masz inne dane na komórkę niż tylko częstotliwość, potrzebujesz dodatkowej pracy.Mam więc zestaw danych z wynikami Z dla współrzędnych X i Y. Jednak obliczałem kilka punktów poza obszarem zainteresowania (duże luki) i stosy punktów w małym obszarze zainteresowania.
Tak, tutaj staje się trudniejsze, ale także przyjemniejsze. Niektóre biblioteki (przepraszam):
pyplot jest dziś moim silnikiem graficznym, cm to szereg map kolorów z pewnym nieciekawym wyborem. numpy do obliczeń i griddata do dołączania wartości do stałej siatki.
Ten ostatni jest ważny, szczególnie, że częstotliwość punktów xy nie jest równomiernie rozłożona w moich danych. Najpierw zacznijmy od pewnych granic pasujących do moich danych i dowolnego rozmiaru siatki. Oryginalne dane mają punkty danych również poza tymi granicami xiy.
Zdefiniowaliśmy więc siatkę z 500 pikselami między wartościami min i max x i y.
W moich danych jest o wiele więcej niż 500 wartości dostępnych w obszarze o dużym zainteresowaniu; mając na uwadze, że w obszarze niskiego zainteresowania nie ma nawet 200 wartości w całej sieci; między granicami graficznymi
x_min
ix_max
jest jeszcze mniej.Aby uzyskać ładny obraz, zadaniem jest uzyskanie średniej dla wysokich wartości zainteresowania i wypełnienie luk gdzie indziej.
Teraz definiuję swoją siatkę. Dla każdej pary xx-yy chcę mieć kolor.
Skąd ten dziwny kształt? scipy.griddata chce mieć kształt (n, D).
Griddata oblicza jedną wartość na punkt w siatce za pomocą predefiniowanej metody. Wybieram „najbliższy” - puste punkty siatki zostaną wypełnione wartościami od najbliższego sąsiada. Wygląda na to, że obszary z mniejszą ilością informacji mają większe komórki (nawet jeśli tak nie jest). Można wybrać interpolację „liniową”, a obszary z mniejszą ilością informacji wyglądają mniej ostro. Naprawdę sprawa gustu.
I hop, przekazujemy matplotlib, aby wyświetlić fabułę
Wokół spiczastej części Kształtu V widać, że wykonałem wiele obliczeń podczas poszukiwania słodkiego miejsca, podczas gdy mniej interesujące części prawie wszędzie indziej mają niższą rozdzielczość.
źródło
Oto podejście najbliższego sąsiada Jurgy'ego, ale zaimplementowane przy użyciu scipy.cKDTree . W moich testach jest około 100 razy szybszy.
źródło
Utwórz dwuwymiarową tablicę, która odpowiada komórkom na ostatecznym obrazie, zwaną say
heatmap_cells
i utwórz ją jako wszystkie zera.Wybierz dwa współczynniki skalowania, które określają różnicę między każdym elementem tablicy w jednostkach rzeczywistych, dla każdego wymiaru, powiedz
x_scale
iy_scale
. Wybierz je w taki sposób, aby wszystkie twoje punkty danych mieściły się w granicach tablicy Heatmap.Dla każdego nieprzetworzonego punktu danych za pomocą
x_value
iy_value
:heatmap_cells[floor(x_value/x_scale),floor(y_value/y_scale)]+=1
źródło
Oto jeden, który wykonałem na zestawie 1 milion punktów z 3 kategoriami (w kolorze czerwonym, zielonym i niebieskim). Oto link do repozytorium, jeśli chcesz wypróbować tę funkcję. Github Repo
źródło
Bardzo podobny do odpowiedzi @ Piti , ale do wygenerowania punktów używa 1 połączenia zamiast 2:
Wynik:
źródło
Obawiam się, że jestem trochę spóźniony na imprezę, ale już kiedyś miałem podobne pytanie. Zaakceptowana odpowiedź (autor @ptomato) pomogła mi, ale chciałbym również zamieścić to na wypadek, gdyby było dla kogoś przydatne.
Oto wynik
źródło