Odpowiedzi:
Pick został stworzony dla takich problemów. Potraktuj to jako wersję „con”, która jest implementacją algebry map „if ... else” w wersji „switch” (lub „case”).
Jeśli na przykład istnieją 3 nakładające się rastry, wyglądałaby składnia (Python)
inPositionRaster = 1 + int(3 * CreateRandomRaster())
Pick(inPositionRaster, [inRas01, inRas02, inRas03])
Pamiętaj, że pick
indeksowanie rozpoczyna się od 1, a nie od 0.
(patrz temat komentarza)
Aby poradzić sobie z wartościami NoData, najpierw musisz wyłączyć obsługę NoData ArcGIS. Zrób to, tworząc siatki, które mają specjalną (ale prawidłową) wartość zamiast NoData, taką jak 99999 (lub cokolwiek innego, ale pamiętaj, aby wybrać wartość większą niż jakikolwiek prawidłowy numer, który może się pojawić: będzie to przydatne później) . To wymaga użycia wniosek IsNull, podobnie jak w
p01 = Con(IsNull(inRas01), 99999, inRas01)
p02 = Con(IsNull(inRas02), 99999, inRas01)
p03 = Con(IsNull(inRas03), 99999, inRas01)
Na przykład rozważmy przypadek tych jednorzędowych siatek (NoData jest pokazana jako „*”):
inRas01: 1 2 19 4 * * * *
inRas02: 9 2 * * 13 14 * *
inRas03: 17 * 3 * 21 * 23 *
Rezultatem jest wstawienie 99999 w miejsce każdego „*”.
Następnie wyobraź sobie te wszystkie rastry jako płaskie tablice drewnianych klocków z NoData odpowiadającymi brakującym blokom (dziurom). Kiedy ustawisz pionowo te rastry, bloki wpadną w dowolne otwory pod nimi. Potrzebujemy takiego zachowania, aby uniknąć wybierania wartości NoData: nie chcemy żadnych pionowych przerw w stosach bloków. Kolejność bloków w każdej wieży tak naprawdę nie ma znaczenia. W tym celu możemy uzyskać każdą wieżę poprzez uszeregowanie danych :
q01 = Rank(1, [p01, p02, p03])
q02 = Rank(2, [p01, p02, p03])
q03 = Rank(3, [p01, p02, p03])
W przykładzie otrzymujemy
q01: 1 2 3 4 13 14 23 99999
q02: 9 2 19 99999 21 99999 99999 99999
q03: 17 99999 99999 99999 99999 99999 99999 99999
Zauważ, że rangi są od najniższej do najwyższej, więc q01 zawiera najniższe wartości w każdej lokalizacji, q02 zawiera drugą najniższą, itd. Kody NoData nie zaczynają się wyświetlać, dopóki wszystkie prawidłowe liczby nie zostaną zebrane, ponieważ te kody są większe niż jakiekolwiek prawidłowe liczby.
Aby uniknąć wybierania tych kodów NoData podczas losowego wyboru, musisz wiedzieć, ile bloków jest ułożonych w stos w każdej lokalizacji: informuje nas o tym, ile prawidłowych wartości występuje. Jednym ze sposobów poradzenia sobie z tym jest policzenie liczby kodów NoData i odjęcie ich od całkowitej liczby siatek wyboru:
n0 = 3 - EqualToFrequency(99999, [q01, q02, q03])
To daje
n0: 3 2 2 1 2 1 1 0
Aby obsłużyć przypadki, w których n = 0 (więc nie ma już nic do wyboru), ustaw je na NoData:
n = SetNull(n0 == 0, n0)
Teraz
n: 3 2 2 1 2 1 1 *
Zagwarantuje to również, że twoje (tymczasowe) kody NoData znikną w końcowym obliczeniu. Wygeneruj losowe wartości od 1 do n:
inPositionRaster = 1 + int(n * CreateRandomRaster())
Na przykład ten raster może wyglądać
inPositionRaster: 3 2 1 1 2 1 1 *
Wszystkie jego wartości mieszczą się w przedziale od 1 do odpowiedniej wartości w [n].
Wybierz wartości dokładnie tak jak poprzednio:
selection = Pick(inPositionRaster, [q01, q02, q03])
Spowodowałoby to
selection: 17 2 3 4 21 14 23 *
Aby sprawdzić, czy wszystko jest w porządku, spróbuj wybrać wszystkie komórki wyjściowe, które mają kod NoData (99999 w tym przykładzie): nie powinno być żadnych.
Chociaż ten działający przykład używa tylko trzech siatek do wyboru, napisałem go w sposób, który łatwo uogólnia na dowolną liczbę siatek. Przy wielu siatkach napisanie skryptu (w celu zapętlenia powtarzających się operacji) będzie nieocenione.
pick
: jeśli inPositionRaster i wybrany raster mają prawidłowe wartości w komórce, to prawdopodobnie wynik dla tej komórki powinna być wartość wybranego rastra, niezależnie od tego, co może zawierać inny raster). O jakim alternatywnym zachowaniu myślisz?
Korzystanie z Pythona i ArcGIS 10 i korzystanie z funkcji con, która ma następującą składnię:
Con (in_conditional_raster, in_true_raster_or_constant, {in_false_raster_or_constant}, {where_clause})
Chodzi tutaj o sprawdzenie, czy wartość w losowym rastrze jest mniejsza niż 0,5, jeśli wybierzesz raster1, w przeciwnym razie wybierz raster2. NoData
+ dane = NoData
więc najpierw ustaw te przeklasyfikuj dowolne wartości NoData
na 0:
import arcpy
from arcpy import env
from arcpy.sa import *
env.workspace = "C:/sapyexamples/data"
ras1_NoNull = Con(IsNull("elevation1"),0, "elevation1") # remove NoData
ras2_NoNull = Con(IsNull("elevation2"),0, "elevation2") # remove NoData
randRaster = CreateRandomRaster(100, 2, Extent(0, 0, 150, 150)) # raster generated between 0 and 1; 100 is seed value
outCon = Con(randRaster < 0.5, ras1_NoNull, ras2_NoNull)
outCon.save("C:/outcon.img") # save raster
EDYCJA: Właśnie zrozumiałem, że nie dodajesz NoData
wartości, aby kawałek mógł zostać pominięty.
Con(IsNull(ras1), 0, ras2)
NoData
? Czy to po prostu upewnić się, że nie zostaną one wybrane podczas losowego wyboru?
Po prostu stworzyłbym losowy raster ( pomoc ) o tym samym zakresie i rozmiarze komórki. Następnie za pomocą CON ( pomoc ) ustaw go, aby wybierał wartość z 1. rastra, jeśli komórka z randomizowanego rastra ma wartość <128 (jeśli losowy raster miałby wartość 0–255), w przeciwnym razie wybierz wartość z 2. rastra.
Mam nadzieję, że to ma sens :)