---
title: 'Grafik Dilbilgisi'
source: 'https://academia.sh/tr/kurslar/python-ile-analiz/grafik-dilbilgisi'
course: 'Python ile Veri Analizi'
language: tr
updated: '2026-08-17T18:08:43+00:00'
license: 'CC BY-SA 4.0'
---

# Grafik Dilbilgisi

Aynı sütun grafiği iki yolla kurulur: hazır bir çağrı 9 bağımsız değişken alır, katmanlı kuruluş 5 katman tutar ve ikisi de aynı değerleri verir. Üzerine bir referans çizgisi eklendiğinde hazır çağrının imzası 9'dan 11'e çıkar ve önceki kurulumdan hiçbir kalem yeniden kullanılmaz; katmanlı kuruluş 5'ten 6 katmana çıkar ve 5 katman aynen kalır. Gizlenen karar istatistik katmanındadır: aynı beş katmanın dördü sabit tutulup yalnız istatistik değiştirildiğinde en uzun çubuk kuzey, doğu ve yine kuzey olur — adet 921, ortalama 24,674 m³, toplam 18.613,81 m³ üç ayrı sıralama üretir. Konum ayarı da aynı biçimde davranır: 6 katman değişmeden dururken doğu/2 için okunan sayı 281'den 0,504'e iner.

Bir önceki ders dönüştürmeyi fiillerden kurdu ve her fiilin bir öncekinin çıktısını aldığını
gösterdi. Görselleştirmede de benzer bir kuruluş vardır, ama parçalar birbirini izlemez —
**üst üste biner**. **Grafik dilbilgisi (grammar of graphics)** bir grafiği tek bir çağrı olarak
değil, birbirinden bağımsız katmanların toplamı olarak ele alır: veri, eşleme, istatistik, geometri,
ölçek, konum.

Bu dersin sayısı katman sayısıdır: aynı grafik hazır bir çağrıyla kurulduğunda kaç kalem yazılıyor,
katmanlarla kurulduğunda kaç katman tutuyor, ve grafik büyüdüğünde kaç kalem yeniden kullanılıyor.
Yanında kursun ikinci sayısı durur: bir katman yazılmadığında onun yerine hangi varsayılan geçiyor
ve grafiğin okunan sayısı ne oluyor.

- **AO9.** Küme K03'ten devralınır ve **kurgudur**: 3.199 satır, 1.329 abone, 10/25/40 m³ tarife
  basamakları. Tohum koda yazılıdır.
- **AO10.** Katmanlı grafik **standart kitaplıkla modellenir**. `Katman` bir tür ve birkaç ayardır,
  `Grafik` bir katman listesidir; çizim metin çubuklarıyla yapılır, çünkü ölçülen şey biçim değil
  **katman sayısıdır**. Hiçbir araç ya da kitaplık taklit edilmez.
- **AO11.** Grafik türünün eksen alanının ölçeğine uyup uymadığı bu derste **ölçülmez**; o soru
  Elektronik Tablolarla Analiz kursunun Temel Grafikler dersinde ölçüldü. Burada tür yalnız bir
  **geometri katmanıdır** ve sayılan şey katmanların sayısı ile birbirinden bağımsız olup olmadığıdır.
- **AO12.** İki sayı yan yana durur. **Kazanç** grafiği genişletirken yeniden kullanılan kalem
  sayısıdır. **Gizlenen karar** yazılmayan katmandır: istatistik ve konum katmanı yazılmadığında
  grafik yine çizilir, ama çubukların boyu başka bir şeyi gösterir.

## Bir Grafik Kaç Katman

```python
# grafik.py — MODELDIR. Once K03'un 3.199 satirlik kurgu kumesi ayni tohumla
# uretilir, sonra katmanli gorsellestirme standart kitaplikla modellenir.
import inspect
import math

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


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

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


def ayrik(u: float, w: list[float]) -> int:
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


_kalan, _elenen = [], []
for i in range(HAM):
    r = uretec(TOHUM + i)
    b = BOLGE[ayrik(r(), [x[1] for x in BOLGE])]
    kayit = {"abone_no": 10001 + i, "bolge": b[0], "taban": b[2],
             "hane_kisi": ayrik(r(), [0.06, 0.24, 0.30, 0.24, 0.11, 0.05]),
             "memnuniyet": ayrik(r(), [0.08, 0.14, 0.27, 0.34, 0.17]) + 1}
    (_elenen if r() < 0.046 else _kalan).append(kayit)
_gecerli = {k["abone_no"] for k in _kalan}
OKUMA = []
for k in _kalan + _elenen:
    r = uretec(TOHUM + 7000 + k["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(
            k["taban"] * math.exp((r() + r() + r() - 1.5) * 0.62) * (1 - d * 0.05) * 100
            + 0.5) / 100
        if k["abone_no"] not in _gecerli:
            r()
            continue
        OKUMA.append({"abone_no": k["abone_no"], "bolge": k["bolge"], "donem": DONEM[d],
                      "tuketim_m3": t, "memnuniyet": k["memnuniyet"],
                      "basamak": 1 if t < TARIFE[0] else 2 if t < TARIFE[1]
                      else 3 if t < TARIFE[2] else 4})
        r()


class Katman:
    """Katmanli gorsellestirmenin MODELI: katman bir tur ve birkac ayardir."""

    def __init__(self, tur, **ayar):
        self.tur, self.ayar = tur, ayar

    def imza(self):
        return (self.tur, tuple(sorted(
            (k, f"{len(v)} satir" if isinstance(v, list) else str(v))
            for k, v in self.ayar.items())))


OZET = {"adet": lambda v, a: float(len(v)),
        "ortalama": lambda v, a: sum(s[a] for s in v) / len(v),
        "toplam": lambda v, a: sum(s[a] for s in v)}


class Grafik:
    def __init__(self, katmanlar=()):
        self.katmanlar = list(katmanlar)

    def ekle(self, *k):
        return Grafik(self.katmanlar + list(k))

    def degistir(self, k):
        return Grafik([k if e.tur == k.tur else e for e in self.katmanlar])

    def ayar(self, tur, **yoksa):
        for k in self.katmanlar:
            if k.tur == tur:
                return {**yoksa, **k.ayar}
        return yoksa

    # Katmanlar sirayla islenir: veri kovalanir, istatistik uygulanir, konum ayarlanir.
    def deger(self):
        veri = self.ayar("veri", satirlar=[])["satirlar"]
        e = self.ayar("eslesme")
        ozet = self.ayar("istatistik", ozet="adet")["ozet"]
        kova = {}
        for s in veri:
            kova.setdefault((s[e["x"]], s[e["renk"]] if "renk" in e else None), []).append(s)
        d = {a: OZET[ozet](v, e["y"]) for a, v in kova.items()}
        if self.ayar("konum", ayar="yigilmis")["ayar"] == "oranli":
            butun = {}
            for (x, _), v in d.items():
                butun[x] = butun.get(x, 0.0) + v
            d = {a: v / butun[a[0]] for a, v in d.items()}
        return d

    def ciz(self, baslik):
        d = self.deger()
        alt = self.ayar("olcek", alt=0.0)["alt"]
        ust = max(d.values())
        print(f"{baslik} — {len(self.katmanlar)} katman")
        for (x, r), v in sorted(d.items(), key=lambda p: -p[1]):
            n = round(24 * (v - alt) / (ust - alt)) if ust > alt else 0
            print(f"  {x if r is None else f'{x}/{r}':<14}{v:9.3f}  " + "#" * max(0, n))
        for k in self.katmanlar:
            if k.tur == "geometri" and k.ayar.get("bicim") == "cizgi":
                v = k.ayar["deger"]
                print(f"  {k.ayar['etiket']:<14}{v:9.3f}  "
                      + "-" * max(0, round(24 * (v - alt) / (ust - alt))))


TEMEL = Grafik().ekle(
    Katman("veri", satirlar=OKUMA),
    Katman("eslesme", x="bolge", y="tuketim_m3"),
    Katman("istatistik", ozet="ortalama"),
    Katman("geometri", bicim="cubuk"),
    Katman("olcek", eksen="y", alt=0.0))
TEMEL.ciz("bolge basina ortalama tuketim (m3)")
```

```
bolge basina ortalama tuketim (m3) — 5 katman
  dogu             24.674  ########################
  merkez           22.396  ######################
  kuzey            20.210  ####################
  guney            16.602  ################
  bati             13.778  #############
```

Grafik beş katmandan kuruldu ve her katman tek bir soruya cevap veriyor. **Veri** katmanı hangi
satırların çizileceğini söyler. **Eşleme** hangi alanın hangi eksene gideceğini söyler. **İstatistik**
katmanı ham satırlardan çizilecek sayının nasıl türetileceğini söyler — burada her bölgenin
ortalaması. **Geometri** katmanı o sayının hangi biçimde çizileceğini, **ölçek** katmanı ekseni
söyler.

Bu ayrımın önemi katmanların **birbirinden bağımsız** olmasıdır. Geometriyi çubuktan noktaya çevirmek
öbür dört katmana dokunmaz; istatistiği ortalamadan adete çevirmek geometriyi değiştirmez. Bir
grafik, seçeneklerin sabit bir listesi değil, birleştirilebilir parçalardan kurulmuş bir cümledir.

Bağımsızlık, katmanların sırasız olduğu anlamına gelmez. `deger` yöntemi işi belli bir sırayla
yapar: önce veri eşlemeye göre kovalara ayrılır, sonra her kovaya istatistik uygulanır, en sonda
konum ayarı uygulanır. Katmanlar sayfaya hangi sırayla yazılırsa yazılsın bu işlem sırası değişmez;
değişen tek şey hangi katmanın listede bulunduğudur. Fiil zincirinde sıra yazımın kendisiydi, burada
sıra dilbilgisinin kuralıdır ve yazımdan okunmaz.

## Katman Eklemek, Çağrıyı Genişletmek

Aynı grafik hazır bir çağrıyla da kurulabilir: bütün kararlar tek bir imzada toplanır ve çağıran
kişi yalnız bağımsız değişkenleri doldurur. İkisinin farkı grafik büyüdüğünde ortaya çıkar.

```python
def hazir_cubuk(satirlar, x, y, ozet, renk=None, konum="yigilmis", alt=0.0, ust=None,
                baslik=""):
    """Hazir cagri MODELI: butun kararlar tek bir imzada toplanir."""
    return Grafik().ekle(Katman("veri", satirlar=satirlar),
                         Katman("eslesme", x=x, y=y),
                         Katman("istatistik", ozet=ozet),
                         Katman("geometri", bicim="cubuk"),
                         Katman("olcek", eksen="y", alt=alt))


# Referans cizgisi eklemek icin imzaya iki bagimsiz degisken daha girmesi gerekir.
def hazir_cubuk_referansli(satirlar, x, y, ozet, renk=None, konum="yigilmis", alt=0.0,
                           ust=None, baslik="", referans=None, referans_etiket=""):
    g = hazir_cubuk(satirlar, x, y, ozet, renk, konum, alt, ust, baslik)
    return g if referans is None else g.ekle(
        Katman("geometri", bicim="cizgi", etiket=referans_etiket, deger=referans))


GENEL = sum(s["tuketim_m3"] for s in OKUMA) / len(OKUMA)
REFERANSLI = TEMEL.ekle(Katman("geometri", bicim="cizgi", etiket="genel ortalama",
                               deger=round(GENEL, 3)))
eski = [k.imza() for k in TEMEL.katmanlar]
kalan = sum(1 for k in REFERANSLI.katmanlar if k.imza() in eski)


def arg(f):
    return len(inspect.signature(f).parameters)


def hiza(w):
    return lambda h: "".join(str(v).ljust(w[0]) if j == 0 else str(v).rjust(w[j])
                             for j, v in enumerate(h))


ayni_mi = hazir_cubuk(OKUMA, "bolge", "tuketim_m3", "ortalama").deger() == TEMEL.deger()
print(f"hazir cagri ile katmanli kurulus ayni degerleri veriyor: "
      f"{'evet' if ayni_mi else 'hayir'}")
y = hiza([22, 16, 22, 22])
print("\n" + y(["kurulus", "temel grafik", "referans eklenince", "yeniden kullanilan"]))
print(y(["hazir cagri (argum.)", arg(hazir_cubuk), arg(hazir_cubuk_referansli), 0]))
print(y(["katman listesi", len(TEMEL.katmanlar), len(REFERANSLI.katmanlar), kalan]))
print()
REFERANSLI.ciz("ayni grafik, referans cizgisi eklenmis")
```

```
hazir cagri ile katmanli kurulus ayni degerleri veriyor: evet

kurulus                   temel grafik    referans eklenince    yeniden kullanilan
hazir cagri (argum.)                 9                    11                     0
katman listesi                       5                     6                     5

ayni grafik, referans cizgisi eklenmis — 6 katman
  dogu             24.674  ########################
  merkez           22.396  ######################
  kuzey            20.210  ####################
  guney            16.602  ################
  bati             13.778  #############
  genel ortalama   19.713  -------------------
```

İlk satır çıpadır: iki kuruluş aynı değerleri verir, yani ölçülen şey sonuç değil **yapıdır**. Hazır
çağrı temel grafiği 9 bağımsız değişkenle kurar, katman listesi 5 katmanla. Sayı olarak hazır çağrı
daha az kalem tutuyor gibi görünmez, ama asıl ayrım ikinci sütunda.

Grafiğe genel ortalamayı gösteren bir çizgi eklendiğinde hazır çağrının **imzası** 9'dan 11'e çıkar.
Bu, o çağrıyı kullanan her yerin gördüğü yeni bir imzadır ve önceki kurulumdan yeniden kullanılan
kalem sayısı **sıfırdır**: çağrı bir bütündür, parçası taşınamaz. Katmanlı kuruluşta liste 5'ten 6'ya
çıkar ve **5 katman aynen kalır**; eklenen tek şey bir geometri katmanıdır. Genişleme burada
listeye, orada imzaya yazılır.

Bunun bir de ters yönü var ve yazılmalıdır. Hazır çağrı, sık kullanılan bir grafiği tek satırda
verir ve beş katmanı elle dizmeyi gerektirmez; katmanlı kuruluşta aynı grafiği kuran herkes aynı beş
katmanı yeniden yazar. Ölçü bir üstünlük sıralaması değildir: hazır çağrı **tekrarı**, katmanlı
kuruluş **genişlemeyi** ucuzlatır.

## İstatistik Katmanı Yazılmazsa

Katmanların bağımsızlığının bedeli, bir katman yazılmadığında grafiğin hata vermeden çizilmesidir.
Model yazılmayan katmanın yerine bir varsayılan koyar ve çubuklar yine görünür.

```python
y2 = hiza([14, 12, 12, 12, 12, 12, 16])
BOLGELER = ("kuzey", "dogu", "merkez", "guney", "bati")
print(y2(["istatistik"] + list(BOLGELER) + ["en uzun cubuk"]))
uzun = []
for ozet in ("adet", "ortalama", "toplam"):
    g = TEMEL.degistir(Katman("istatistik", ozet=ozet))
    d = {a[0]: v for a, v in g.deger().items()}
    uzun.append(max(d.items(), key=lambda p: p[1])[0])
    print(y2([ozet] + [f"{d[b]:.3f}" for b in BOLGELER] + [uzun[-1]]))
print(f"\nayni {len(TEMEL.katmanlar)} katmanin dordu ayni; yalniz istatistik katmani "
      f"degisti ve en uzun cubuk {' -> '.join(uzun)} oldu")

RENKLI = Grafik([Katman("veri", satirlar=OKUMA),
                 Katman("eslesme", x="bolge", y="tuketim_m3", renk="basamak"),
                 Katman("istatistik", ozet="adet"),
                 Katman("geometri", bicim="cubuk"),
                 Katman("olcek", eksen="y", alt=0.0)])
y3 = hiza([14, 12, 12, 12, 12])
print("\n" + y3(["konum ayari", "dogu/1", "dogu/2", "dogu/3", "dogu/4"]))
ikinci = []
for ayar in ("yigilmis", "oranli"):
    d = RENKLI.ekle(Katman("konum", ayar=ayar)).deger()
    ikinci.append(d[("dogu", 2)])
    print(y3([ayar] + [f"{d[('dogu', b)]:.3f}" for b in (1, 2, 3, 4)]))
print(f"\nkatman sayisi {len(RENKLI.katmanlar) + 1} her iki ayarda da ayni; tek bir "
      f"katmanin tek ayari degisti ve dogu/2 icin okunan sayi {ikinci[0]:.0f} yerine "
      f"{ikinci[1]:.3f} oldu")
```

```
istatistik           kuzey        dogu      merkez       guney        bati   en uzun cubuk
adet               921.000     557.000     600.000     645.000     476.000           kuzey
ortalama            20.210      24.674      22.396      16.602      13.778            dogu
toplam           18613.810   13743.340   13437.310   10708.020    6558.150           kuzey

ayni 5 katmanin dordu ayni; yalniz istatistik katmani degisti ve en uzun cubuk kuzey -> dogu -> kuzey oldu

konum ayari         dogu/1      dogu/2      dogu/3      dogu/4
yigilmis            21.000     281.000     225.000      30.000
oranli               0.038       0.504       0.404       0.054

katman sayisi 6 her iki ayarda da ayni; tek bir katmanin tek ayari degisti ve dogu/2 icin okunan sayi 281 yerine 0.504 oldu
```

Üç satır aynı veriyi, aynı eşlemeyi, aynı geometriyi ve aynı ölçeği kullanıyor. Değişen tek şey
istatistik katmanıdır ve grafiğin söylediği şey üç kez değişiyor. Adet seçildiğinde en uzun çubuk
kuzeydedir, çünkü kuzeyde 921 okuma vardır. Ortalama seçildiğinde en uzun çubuk doğuya geçer,
çünkü doğu 557 okumayla en az kalabalık ama en yüksek tüketimli bölgedir. Toplam seçildiğinde çubuk
kuzeye geri döner. Üçü de doğrudur ve **üçü de aynı sütun grafiğidir**; hangisinin çizildiğini
söyleyen tek şey yazılmış ya da yazılmamış olan istatistik katmanıdır.

Konum ayarı aynı davranışı bir kez daha gösterir. Altı katman iki koşumda da birebir aynıdır; tek
fark konum katmanının ayarıdır. Yığılmış ayarda doğu bölgesinin ikinci tarife basamağında **281
okuma** vardır ve çubuğun boyu bir sayıdır. Oranlı ayarda aynı yer **0,504** olur ve çubuğun boyu
bir paydır. Bir okuyucu ikinci grafiğe bakıp "doğuda ikinci basamak yarıya yakın" der ve haklıdır;
ilkine bakıp "doğuda ikinci basamakta 281 okuma var" der ve o da haklıdır. Kaç okuma olduğu ikinci
grafikten, payın ne olduğu ilkinden okunamaz.

Kursun kuralı grafikte de aynen geçerlidir: bir soyutlama işi kısalttığı kadar kararı da gizler.
Katmanlı kuruluşun sağladığı şey kararların **adlandırılmış** olmasıdır — istatistik bir katmandır,
konum bir katmandır ve grafiğin listesine bakan biri hangisinin yazıldığını görebilir. Yazılmayan
katman ise varsayılana düşer ve grafik yine çizilir; sayfaya bakan kişinin elinde çubuğun neyi
ölçtüğünü söyleyen bir kayıt kalmaz.

## Özet

- Aynı sütun grafiği hazır çağrıyla 9 bağımsız değişkende, katmanlı kuruluşla 5 katmanda kurulur ve
  ikisi de aynı değerleri verir.
- Referans çizgisi eklendiğinde hazır çağrının imzası 9'dan 11'e çıkar ve yeniden kullanılan kalem
  sayısı 0'dır; katman listesi 5'ten 6'ya çıkar ve 5 katman aynen kalır.
- Hazır çağrı tekrarı, katmanlı kuruluş genişlemeyi ucuzlatır; ölçü bir üstünlük sıralaması değildir.
- İstatistik katmanı değiştiğinde grafiğin dört katmanı sabit kalır ama en uzun çubuk kuzey, doğu ve
  yine kuzey olur: adet 921, ortalama 24,674 m³, toplam 18.613,81 m³.
- Konum ayarı katman sayısını değiştirmeden okunan sayıyı değiştirir: doğu bölgesinin ikinci
  basamağı yığılmış ayarda 281, oranlı ayarda 0,504 olarak okunur.

## Sonraki Adım

Üç ders üç yaklaşımı ölçtü: aynı analizin kaç deyimde ifade edildiği, dönüştürmenin kaç fiil ve kaç
ara değişkenle yazıldığı, grafiğin kaç katmanla kurulduğu. Hepsinde ölçü ifadenin biçimiydi ve
hiçbirinde bir ortamın öbüründen iyi olduğu söylenmedi. Geriye seçimin kendisi kalıyor: bir ekip
hangi ortamda çalışacağına neye bakarak karar verir. Sonraki ders bunu ölçüte bağlar — ekibin eldeki
becerisi, çevresindeki hazır parçaların kapsamı ve işin üretime taşınabilirliği — ve üç ortamı üç
ölçütte sayıyla karşılaştırıp seçimin hangi ölçütte değiştiğini yazar. Kurs orada kapanır ve yirmi
iki dersin kazancıyla gizlenen kararını tek bir tabloda sayar.
