İçeriğe geç
academia.sh

Ders 06 / 18

Coğrafi Görselleştirme

Beş bölge 12x12'lik bir kapsama ızgarasında beş renk basamağıyla kodlanıyor ve okuyucunun geri okuduğu şey basamak değil basamağın kapladığı alan oluyor: okuma sayısıyla ağırlıklı doğru ortalama 19,713 m³ iken alanla ağırlıklı geri okuma 18,484 m³ veriyor ve fark -1,228 m³. Batı, okumaların yüzde 14,9'unu ve alanın yüzde 25'ini taşıdığı için 1,680 ağırlık çarpanı alıyor. İzdüşüm esnemesi eşit alanlı iki bölgeyi 1,237 kat farklı bastırıyor. Alan payı okuma payına eşitlendiğinde hata 0,396 m³'e iniyor, bedeli 93 hücrenin bölge değiştirmesi ve komşu bölge çiftinin 8'den 4'e düşmesidir.

İçindekiler

Önceki ders ekseni zamana çevirdi ve kanalın taşıdığı şeyin değişim olduğunu ölçtü. Ölçüm ağının her okuması bir yerde de alınıyor ve o yer tek boyutlu bir eksen değil, iki boyutlu bir alandır. Alan üzerine kurulan bir gösterimde değer bir renk basamağına çevrilir ve okuyucu basamağı geri okur. Ama okuyucunun gözüne giren şey basamak değil, basamağın kapladığı alandır.

Bu dersin ölçüsü budur: alan boyalı bir gösterimden geri okunan sayı ile veride bulunan sayı arasındaki fark, ve bu farkın bölgelerin alanıyla nasıl orantılı olduğu. Renk basamağı kanalının kaç ayrı düzeyi geri okuttuğu ilişki görselleştirme dersinde ölçüldü; burada basamak sayısı beşte sabit tutulur ve değişken alandır. Hiçbir gerçek yer, harita ürünü ya da izdüşüm adı yazılmaz; kapsama alanı bir ızgara olarak modellenir.

  • GT31. Kapsama ızgarası kurgudur. Ağın bölgeleri 12x12’lik bir hücre ızgarasına bölünür; her hücre bir kapsama birimidir ve bölünme koda yazılıdır.
  • GT32. Alan boyalı gösterimde kanal renk basamağıdır. Kodlayıcı değeri eşit genişlikli beş dilimden birine, çözücü dilimin ortasına eşler; okuma çözünürlüğü dilim genişliğidir ve okuyucu dilim içindeki yeri ayırt edemediği için bu sayı geri okunamayan payı verir.
  • GT33. Geri okuma alanla ağırlıklanır. Bir bakışta okunan ortalama, bölge ortalamalarının hücre sayısıyla ağırlıklı ortalamasıdır. Doğru sayı ise okuma sayısıyla ağırlıklı olandır.
  • GT34. Ağırlık çarpanı bölgenin alan payının okuma payına bölümüdür. Çarpan birden büyükse bölge hak ettiğinden fazla, küçükse hak ettiğinden az okunur.
  • GT35. İzdüşüm esnemesi eşit alanları eşit basmaz. Eğri bir yüzey dikdörtgen bir ızgaraya basıldığında satırlar eşit genişlikte basılmaz; esneme çarpanı modelde satır numarasının işlevidir ve koda yazılıdır.
  • GT36. Alan payı düzeltilebilir, komşuluk düzeltilemez. Hücreler okuma payıyla orantılı dağıtıldığında alan ağırlığı ortadan kalkar, ama ızgaranın hangi bölgenin hangisine komşu olduğu bilgisi bozulur ve bozulma çift sayısıyla ölçülür.

Izgara ve Renk Basamağı

# izgara.py — MODELDIR: K03-K05'in kurgu olcum agi ayni tohumla uretilir.
# Agin kapsama alani da KURGUDUR: 12x12'lik bir hucre izgarasidir ve her hucre
# bir kapsama birimidir. Hicbir gercek yer, harita ya da izdusum anilmaz.
import math

TOHUM, HAM, M32 = 20260218, 1400, 0xFFFFFFFF
DONEM = ["2026-01", "2026-02", "2026-03"]
BOLGE = [("kuzey", 0.28, 21), ("guney", 0.22, 17), ("dogu", 0.18, 26),
         ("bati", 0.14, 14), ("merkez", 0.18, 23)]


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def ayrik(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


_k, _e = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05])
    ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17])
    (_e if r() < 0.046 else _k).append(
        {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2]})
GECERLI = {a["abone_no"] for a in _k}

OKUMA = []
for a in _k + _e:
    r = uretec(TOHUM + 7000 + a["abone_no"])
    for d in range(ayrik(r(), [0.05, 0.12, 0.21, 0.62])):
        t = 0.0 if r() < 0.038 else math.floor(
            a["taban"] * math.exp((r() + r() + r() - 1.5) * 0.62)
            * (1 - d * 0.05) * 100 + 0.5) / 100
        if a["abone_no"] not in GECERLI:
            r()
            continue
        OKUMA.append({"abone_no": a["abone_no"], "bolge": a["bolge"],
                      "donem": DONEM[d], "tuketim_m3": t})
        r()

AD = [b[0] for b in BOLGE]
SAYIM = {a: sum(1 for o in OKUMA if o["bolge"] == a) for a in AD}
DEGER = {a: sum(o["tuketim_m3"] for o in OKUMA if o["bolge"] == a) / SAYIM[a]
         for a in AD}

# Kapsama izgarasi: 12x12, her hucre bir bolgeye ait. Kurgu bir bolunmedir.
BOY, BASAMAK = 12, 5


def hucre_bolge(i, j):
    if i < 3:
        return "kuzey"
    if j < 4:
        return "bati"
    if i >= 8:
        return "guney"
    if j >= 9:
        return "dogu"
    return "merkez"


IZGARA = [[hucre_bolge(i, j) for j in range(BOY)] for i in range(BOY)]
ALAN = {a: sum(r.count(a) for r in IZGARA) for a in AD}
ENAZ, ENCOK = min(DEGER.values()), max(DEGER.values())
ADIM = (ENCOK - ENAZ) / BASAMAK


def kodla(v):
    """Kodlayici: deger -> renk basamagi. Esit genislikli BASAMAK dilim."""
    return min(BASAMAK - 1, int((v - ENAZ) / ADIM))


def coz(b):
    """Cozucu: renk basamagi -> deger. Okuyucu dilimin ortasini okur."""
    return ENAZ + (b + 0.5) * ADIM


print(f"izgara {BOY}x{BOY} = {BOY * BOY} hucre, {BASAMAK} renk basamagi, "
      f"okuma cozunurlugu {ADIM:.3f} m3/basamak")
print("bolge   alan(hucre)  okuma  ortalama  basamak  geri okunan  hata")
for a in AD:
    b = kodla(DEGER[a])
    print(f"{a:7s} {ALAN[a]:11d} {SAYIM[a]:6d} {DEGER[a]:9.3f} {b:8d} "
          f"{coz(b):12.3f} {coz(b) - DEGER[a]:+6.3f}")
for i in range(BOY):
    print("       " + "".join(str(kodla(DEGER[IZGARA[i][j]])) for j in range(BOY)))
izgara 12x12 = 144 hucre, 5 renk basamagi, okuma cozunurlugu 2.179 m3/basamak
bolge   alan(hucre)  okuma  ortalama  basamak  geri okunan  hata
kuzey            36    921    20.210        2       19.226 -0.985
guney            32    645    16.602        1       17.046 +0.445
dogu             15    557    24.674        4       23.584 -1.090
bati             36    476    13.778        0       14.867 +1.090
merkez           25    600    22.396        3       21.405 -0.991
       222222222222
       222222222222
       222222222222
       000033333444
       000033333444
       000033333444
       000033333444
       000033333444
       000011111111
       000011111111
       000011111111
       000011111111

Basamak sütunu kanalın tamamıdır: beş bölge beş ayrı basamağa düştü ve her biri ayırt edilebilir. Bölge başına geri okuma hatası -1,090 ile +1,090 m³ arasında, yani en çok dilim genişliğinin yarısı kadar. Bu, renk basamağı kanalının bilinen ve sınırlı bedelidir.

Alttaki ızgara asıl sorunu gösteriyor. Doğunun basamağı 4’tür, ızgaranın en yüksek değeri, ama sayfada yalnız 15 hücre kaplıyor. Batının basamağı 0’dır ve 36 hücre kaplıyor. Aynı ızgaraya bakan biri “bu ağ düşük tüketiyor” izlenimi alır; sayfada en çok yer kaplayan basamak en düşük olandır. Bölge başına hata bunu hiçbir biçimde bildirmez, çünkü hata bölge bölge ölçülür ve okuyucu bölge bölge bakmaz.

Alan Ağırlığı

# agirlik.py — okuyucunun bir bakista geri okudugu sey basamak degil, basamagin
# kapladigi alandir. Iki ortalama yan yana konur.
TOPLAM = sum(SAYIM.values())
dogru = sum(DEGER[a] * SAYIM[a] for a in AD) / TOPLAM
bakis = sum(coz(kodla(DEGER[a])) * ALAN[a] for a in AD) / (BOY * BOY)
duz = sum(coz(kodla(DEGER[a])) for a in AD) / len(AD)
print(f"okuma sayisiyla agirlikli ortalama  {dogru:.3f} m3  ({TOPLAM} okuma)")
print(f"bolge basina duz ortalama           {duz:.3f} m3  ({len(AD)} bolge)")
print(f"alanla agirlikli geri okuma         {bakis:.3f} m3  ({BOY * BOY} hucre)")
print(f"alan agirliginin actigi fark        {bakis - dogru:+.3f} m3")
print("bolge   okuma payi  alan payi  agirlik carpani")
for a in AD:
    op, ap = SAYIM[a] / TOPLAM, ALAN[a] / (BOY * BOY)
    print(f"{a:7s} {op * 100:9.1f}% {ap * 100:9.1f}% {ap / op:16.3f}")
okuma sayisiyla agirlikli ortalama  19.713 m3  (3199 okuma)
bolge basina duz ortalama           19.226 m3  (5 bolge)
alanla agirlikli geri okuma         18.484 m3  (144 hucre)
alan agirliginin actigi fark        -1.228 m3
bolge   okuma payi  alan payi  agirlik carpani
kuzey        28.8%      25.0%            0.868
guney        20.2%      22.2%            1.102
dogu         17.4%      10.4%            0.598
bati         14.9%      25.0%            1.680
merkez       18.8%      17.4%            0.926

Üç ortalama, aynı veriden ve hiçbiri hatalı hesaplanmadan. 3.199 okumanın ortalaması 19,713 m³; bölge başına düz ortalama 19,226; alan boyalı gösterimden okunan 18,484. Alan ağırlığının açtığı fark -1,228 m³’tür ve tek bir okuma değişmedi.

Alt tablo farkın nereden geldiğini bölge bölge yazıyor. Batı, okumaların yüzde 14,9’unu taşıyor ama alanın yüzde 25’ini kaplıyor; ağırlık çarpanı 1,680’dir, yani sayfada gerçek payının yaklaşık iki katı kadar konuşuyor. Doğu ise tersine 0,598 çarpanla, payının yarısından biraz fazlası kadar. Batının en düşük, doğunun en yüksek ortalamaya sahip olması bir rastlantıdır, ama iki rastlantı aynı yöne çalışınca geri okunan sayı bir tarafa kayar.

Bu, kanalın seçiminden bağımsız bir kusur değildir; alan kanalının tanımıdır. Renk basamağı alana boyanır ve alan zaten sabittir, veriyle ilgisi yoktur. Gösterim, tasarımcının seçmediği bir ağırlıklandırma uygular ve o ağırlığı hiçbir yere yazmaz.

İzdüşüm Esnemesi

# esneme.py — egri bir yuzey dikdortgen bir izgaraya basildiginda satirlar esit
# genislikte basilmaz. Esneme carpani MODELDIR: ust satirlar daha genis basilir.
BUKUM, REF = 0.07, BOY - 1


def esneme(i):
    return 1.0 / math.cos(BUKUM * (REF - i))


BASILAN = {a: sum(esneme(i) for i in range(BOY) for j in range(BOY)
                  if IZGARA[i][j] == a) for a in AD}
TOPLAM_ALAN = sum(BASILAN.values())
esnek = sum(coz(kodla(DEGER[a])) * BASILAN[a] for a in AD) / TOPLAM_ALAN
print(f"esneme carpani en ust satirda {esneme(0):.3f}, en alt satirda "
      f"{esneme(BOY - 1):.3f}")
print("bolge   gercek alan  basilan alan  buyume")
for a in AD:
    print(f"{a:7s} {ALAN[a]:11d} {BASILAN[a]:13.2f} "
          f"{BASILAN[a] / ALAN[a] - 1:+7.1%}")
print(f"kuzey ile bati esit alanli ({ALAN['kuzey']} hucre) ama basilan alanlari "
      f"{BASILAN['kuzey'] / BASILAN['bati']:.3f} kat farkli")
print(f"esnemeden once alanla agirlikli geri okuma {bakis:.3f} m3, "
      f"sonra {esnek:.3f} m3")
print(f"dogru sayiya uzaklik: {abs(bakis - dogru):.3f} -> "
      f"{abs(esnek - dogru):.3f} m3")
esneme carpani en ust satirda 1.393, en alt satirda 1.000
bolge   gercek alan  basilan alan  buyume
kuzey            36         47.26  +31.3%
guney            32         32.28   +0.9%
dogu             15         16.54  +10.3%
bati             36         38.19   +6.1%
merkez           25         27.57  +10.3%
kuzey ile bati esit alanli (36 hucre) ama basilan alanlari 1.237 kat farkli
esnemeden once alanla agirlikli geri okuma 18.484 m3, sonra 18.579 m3
dogru sayiya uzaklik: 1.228 -> 1.133 m3

Esneme, alan ağırlığının üzerine binen ikinci bir çarpıtmadır ve bu kez tasarımcının kararı bile değildir: eğri bir yüzeyi düz bir ızgaraya basmanın kaçınılmaz bedelidir. Modelde en üst satır en alt satırın 1,393 katı genişlikte basılıyor.

Beşinci satır ölçünün en açık ifadesidir. Kuzey ile batı eşit alanlıdır, ikisi de 36 hücre. Basıldıklarında 47,26 ile 38,19 oluyor, yani aynı büyüklükteki iki bölge 1,237 kat farklı büyüklükte görünüyor. Bir okuyucunun iki bölgenin ağırlığını karşılaştırması için hiçbir dayanağı yok.

Son iki satır dikkatle okunmalı. Esneme bu kurguda toplam hatayı 1,228’den 1,133 m³’e düşürüyor. Bu bir düzeltme değil, bir rastlantıdır: en çok esneyen bölge kuzeydir ve kuzeyin geri okunan değeri doğru sayıya yakın olduğu için ortalamayı yukarı çekmiştir. Esnemenin işareti, bölgelerin ızgarada nerede durduğuna bağlıdır ve tasarımcının denetiminde değildir. Hatayı azaltması da artırması kadar tesadüfidir; ölçülmesi gereken şey toplam değil, bölge başına basılan alan sapmasıdır.

Alan Payını Düzeltmek

# kartogram.py — hucreler okuma payiyla orantili yeniden dagitilir. Alan
# agirligi duzelir, izgaranin komsuluk yapisi bozulur.
kota = {a: SAYIM[a] * BOY * BOY / TOPLAM for a in AD}
pay = {a: int(kota[a]) for a in AD}
for a in sorted(AD, key=lambda x: kota[x] - int(kota[x]), reverse=True):
    if sum(pay.values()) < BOY * BOY:
        pay[a] += 1
akan = [a for a in AD for _ in range(pay[a])]
KART = [akan[i * BOY:(i + 1) * BOY] for i in range(BOY)]
YENI = {a: sum(r.count(a) for r in KART) for a in AD}
kartbakis = sum(coz(kodla(DEGER[a])) * YENI[a] for a in AD) / (BOY * BOY)
tasinan = sum(1 for i in range(BOY) for j in range(BOY)
              if IZGARA[i][j] != KART[i][j])


def komsuluk(g):
    c = set()
    for i in range(BOY):
        for j in range(BOY):
            for di, dj in ((0, 1), (1, 0)):
                x, y = i + di, j + dj
                if x < BOY and y < BOY and g[i][j] != g[x][y]:
                    c.add(tuple(sorted((g[i][j], g[x][y]))))
    return c


k1, k2 = komsuluk(IZGARA), komsuluk(KART)
print("bolge   eski alan  kartogram alan  okuma payi")
for a in AD:
    print(f"{a:7s} {ALAN[a]:9d} {YENI[a]:15d} {SAYIM[a] / TOPLAM * 100:10.1f}%")
for i in range(BOY):
    print("       " + "".join(str(kodla(DEGER[KART[i][j]])) for j in range(BOY)))
print(f"alanla agirlikli geri okuma {bakis:.3f} -> {kartbakis:.3f} m3, "
      f"dogru sayi {dogru:.3f}")
print(f"hata {abs(bakis - dogru):.3f} -> {abs(kartbakis - dogru):.3f} m3; "
      f"{tasinan} hucre bolge degistirdi")
print(f"komsu bolge cifti {len(k1)} -> {len(k2)}; kaybolan "
      f"{len(k1 - k2)}, uydurulan {len(k2 - k1)}")
bolge   eski alan  kartogram alan  okuma payi
kuzey          36              42       28.8%
guney          32              29       20.2%
dogu           15              25       17.4%
bati           36              21       14.9%
merkez         25              27       18.8%
       222222222222
       222222222222
       222222222222
       222222111111
       111111111111
       111111111114
       444444444444
       444444444444
       000000000000
       000000000333
       333333333333
       333333333333
alanla agirlikli geri okuma 18.484 -> 19.317 m3, dogru sayi 19.713
hata 1.228 -> 0.396 m3; 93 hucre bolge degistirdi
komsu bolge cifti 8 -> 4; kaybolan 6, uydurulan 2

Düzeltme basittir: her bölgeye okuma payıyla orantılı sayıda hücre verilir. Doğunun alanı 15’ten 25’e çıkar, batının 36’dan 21’e iner. Geri okuma hatası 1,228’den 0,396 m³’e düşer, yani üçte birine. Kalan 0,396 alan ağırlığından değil, renk basamağının 2,179 m³’lük çözünürlüğünden gelir ve alan düzeltmesiyle kapatılamaz.

Bedel iki sayıyla yazılıdır. Birincisi 144 hücrenin 93’ünün bölge değiştirmesidir; ızgaranın üçte ikisi artık başlangıçtaki yerinde değil. İkincisi daha ağırdır: özgün ızgarada 8 komşu bölge çifti vardı, kartogramda 4 kaldı. Altı komşuluk kayboldu ve iki tane de var olmayan komşuluk uyduruldu. Kartogram doğru sayıyı geri okutur, ama “hangi bölge hangisine bitişik” sorusunun yanıtını bozar; okuyucu ikinci soruyu da bu gösterimden sorabileceğini varsayarsa yeni bir yanlışa düşer.

Karar kuralı buradan çıkar. Alan üzerine kurulan bir gösterim iki sayı olmadan raporlanamaz: bölgenin alan payı ile okuma payının oranı ve renk basamağının çözünürlüğü. Alan payı düzeltilirse komşuluk kaybının kaç çift olduğu da yazılır, çünkü düzeltme başka bir soruyu okunamaz hale getirmiştir.

Özet

  • Alan boyalı gösterimde kanal renk basamağıdır; beş basamak 2,179 m³’lük bir okuma çözünürlüğü verir ve bölge başına geri okuma hatası en çok 1,090 m³’tür.
  • Okuyucunun bir bakışta geri okuduğu sayı alanla ağırlıklıdır: 3.199 okumanın doğru ortalaması 19,713 m³ iken gösterimden okunan 18,484 m³ çıkıyor, fark -1,228 m³.
  • Ağırlık çarpanı alan payının okuma payına bölümüdür; batı 1,680, doğu 0,598 çarpan alıyor ve gösterim bu ağırlığı hiçbir yere yazmıyor.
  • İzdüşüm esnemesi eşit alanlı kuzey ile batıyı 1,237 kat farklı bastırıyor; toplam hatayı bu kurguda 0,095 m³ azaltması bir rastlantıdır ve işareti tasarımcının denetiminde değildir.
  • Alan payı okuma payına eşitlendiğinde hata 0,396 m³’e iniyor; bedeli 93 hücrenin yer değiştirmesi ve komşu bölge çiftinin 8’den 4’e düşmesidir.

Sonraki Adım

Bu derste ölçülen çarpıtmanın hiçbiri bir tercihten doğmadı: alan ızgarada verilidir, esneme düz bir yüzeye basmanın bedelidir. Yine de geri okunan sayı 1,228 m³ kaydı. Sonraki ders aynı soruyu tersinden sorar ve dört çarpıtmayı bir aile olarak ele alır — eksen kırpma, alan kanalının oranı karesiyle büyütmesi, ikili eksen ve düzensiz aralık aynı veriye sırayla uygulanır ve her birinin geri okuma hatası ayrı ayrı basılır. Dördü de savunulabilir bir varsayılan davranıştan doğar; gösterilecek olan, yanıltmanın kasıt gerektirmediğidir.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat