İçeriğe geç

Ders VG-08 · Veri Görselleştirme

Kodla renk: Python ve D3 uygulamaları

UygulamaBeceri ve yöntem, adım adım

İleri · 1.812 kelime · yaklaşık 8 dakika okuma · seslendirme 13 dk

Bu dersin sonunda: yaygın görselleştirme kütüphanelerinde paletleri doğru tanımlar ve özelleştirir.

Önerilen ön ders: VG-01 Veri tipine göre palet: sıralı, ıraksak, kategorik, VG-03 Doğruyu söyleyen renk haritaları

  • renk döngüsü
  • kategori ölçeği
  • örtük tanım alanı
  • renk haritası
  • normalleştirme
  • stil dosyası
Önce özete göz atDersin sonundaki özet, okumaya başlamadan önce yol haritası olarak.
  1. matplotlib'in renk döngüsü ve D3'ün örtük tanım alanlı kategori ölçeği renkleri karşılaşma sırasıyla dağıtır; bu yüzden aynı kategori farklı grafiklerde farklı renk alabilir.
  2. Kategori renkleri Python'da bir sözlükle, D3'te açık bir tanım alanı ve bilinmeyen değer için bir gri ile sabitlenir; sayısal verilerde renk haritasıyla birlikte normalleştirme sınırları ve ıraksak veride orta nokta da sabitlenir. Stil dosyası ya da ortak ölçek nesnesi bu kararları tek yerde tutar.
  3. Örnekte varsayılan döngünün yeşil–kırmızı çifti döteranopide ΔE00 4,6'ya inerken dört ten paleti 15,6'da kalır; ama açıklığa dayalı bir palet sıra ima eder ve doğrudan etiket gerektirir.

Kısa cevap

Görselleştirme kütüphaneleri, renk belirtilmediğinde kategorilere renkleri çoğu zaman karşılaştıkları sırayla dağıtır: matplotlib'de ilk çizilen seri ilk rengi, D3'ün kategori ölçeğinde ilk görülen değer aralıktaki ilk rengi alır. Bu yüzden aynı kategori, veri farklı sırayla geldiğinde iki grafikte iki ayrı renge boyanabilir ve okur, bir grafikte öğrendiği renk anlamını öbüründe yanlış okur. Kategori renkleri bu nedenle bütün grafiklerde sabitlenir: Python'da kategoriyi renge bağlayan bir sözlükle, D3'te ölçeğe tanım alanını açıkça vererek, ortak bir stil dosyasıyla ya da ortak bir ölçek nesnesiyle.

Renk koddan nasıl çıkar?

VG-01 veri tipine göre palet seçimini, VG-06 bir gösterge panelinde kategori renklerinin neden sabit tutulması gerektiğini anlatmıştı. Bu ders aynı ilkelerin kodda nasıl uygulandığını gösteriyor. Örnekler Python'un matplotlib kütüphanesiyle ve JavaScript'in D3 kütüphanesinin renk ölçekleriyle yazıldı ve dersin hazırlanması sırasında matplotlib 3.9.4, d3-scale 4.0.2 ve d3-scale-chromatic 3.1.0 sürümleriyle tek tek çalıştırıldı; ders metnindeki çıktılar bu çalıştırmalardan alındı.

Bir kütüphane renkle iki tür veriyi eşler. Kategorik veride her değer ayrı bir renk alır; bunun için bir renk listesi gerekir. Sayısal veride her değer sürekli bir renk haritasındaki bir noktaya karşılık gelir; bunun için bir renk haritası ve değerleri bu haritaya yerleştiren bir ölçek gerekir. İki durumda da kütüphanenin varsayılan davranışı vardır ve varsayılanı bilmek, onu ne zaman geçersiz kılmak gerektiğini bilmektir.

matplotlib'in varsayılanları

matplotlib'in 2.0 sürümüyle gelen varsayılan stil değişiklikleri belgesi, iki kararı açıkça kaydeder. Bu iki varsayılan, dersin sınandığı 3.9.4 sürümünde de geçerlidir: rengi belirtilmeyen her çizgi category10 döngüsünden, her ısı haritası viridis'ten renk alır.

Bu varsayılanı kodla doğrulamak kolaydır ve doğrulamak, bir paletin nereden geldiğini bilmenin en güvenilir yoludur. Varsayılan döngünün ilk renkleri, çalıştırıldığında şöyle okunur.

1. plt.rcParams["axes.prop_cycle"].by_key()["color"][:4] ifadesi ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'] listesini, yani mavi, turuncu, yeşil ve kırmızıyı döndürür.

Döngü sıraya bağlıdır. Aynı iki şehri iki ayrı grafikte, farklı sırayla çizelim.

  1. Birinci grafikte for sehir in ["Ankara", "İzmir"]: ax.plot([0, 1], [0, 1], label=sehir) çalıştırıldığında Ankara #1f77b4 (mavi), İzmir #ff7f0e (turuncu) olur.
  2. İkinci grafikte döngü for sehir in ["İzmir", "Ankara"]: biçiminde yazıldığında İzmir #1f77b4 (mavi), Ankara #ff7f0e (turuncu) olur.

Kod hatasızdır, grafikler de ayrı ayrı doğrudur; ama iki grafiği yan yana gören okur için Ankara'nın rengi değişmiştir. Verinin sırası bir sorgunun sonucuna, bir filtreye ya da alfabetik sıralamaya bağlıysa bu değişim fark edilmeden olur.

Kategori renklerini sabitlemek: Python

Çözüm, rengi sıradan değil kategorinin adından türetmektir. VG-06'da sabit kategori rengi olarak tanımlanan ilke, kodda bir sözlüktür.

  1. renkler = {"Ankara": "#1f77b4", "İzmir": "#ff7f0e", "Bursa": "#2ca02c"} satırı her şehri bir kez, bir renge bağlar.
  2. Çizim döngüsünde renk açıkça verilir: ax.plot([0, 1], [0, 1], label=sehir, color=renkler[sehir]).
  3. Döngü ["İzmir", "Ankara"] sırasıyla çalıştırıldığında da İzmir #ff7f0e, Ankara #1f77b4 kalır.

Sözlüğün iki yararı daha vardır. Bir kategori veride hiç yoksa, rengi başka bir kategoriye kaymaz; yeni bir kategori eklendiğinde de sözlükte yoksa kod bir hata verir ve renk sessizce atanmaz. Sözlük bir modülde tutulup bütün grafiklerde içe aktarıldığında, projenin kategori renkleri tek bir yerde yaşar.

Kurumsal bir paleti olan projelerde varsayılan döngü yerine kurumun renkleri istenebilir. Döngünün kendisini değiştirmek bunun için yeterlidir.

  1. from cycler import cycler ile döngü nesnesi içe aktarılır.
  2. plt.rcParams["axes.prop_cycle"] = cycler(color=["#1f77b4", "#ff7f0e", "#2ca02c"]) bütün yeni eksenlerin döngüsünü değiştirir.

Ama bu yalnız renklerin hangi sırayla dağıtılacağını değiştirir; kategoriyle renk arasındaki bağı kurmaz. Sabitleme için sözlük gerekir.

Kategori renklerini sabitlemek: D3

D3'te kategorik renkler bir ölçekle eşlenir. Ölçek, bir değer alıp bir renk döndüren bir işlevdir: tanım alanı girdileri, aralık ise çıktı renklerini tutar.

D3'ün belgesi bu ölçeğin varsayılan davranışını açıkça yazar. Bu davranış hızlı bir taslak çizim için bir kolaylıktır, ama kalıcı bir renk anlamı kurmaz.

matplotlib örneğini D3'te tekrarlayalım. Aynı iki şehri iki ayrı ölçekle, farklı sırayla renklendirelim.

  1. const a = d3.scaleOrdinal(schemeCategory10) ölçeğinde önce a("Ankara"), sonra a("İzmir") çağrılınca Ankara #1f77b4, İzmir #ff7f0e olur.
  2. const b = d3.scaleOrdinal(schemeCategory10) ölçeğinde önce b("İzmir"), sonra b("Ankara") çağrılınca İzmir #1f77b4, Ankara #ff7f0e olur.

Çözüm, tanım alanını açıkça vermektir. Tanım alanı verildiğinde ölçek artık çağrı sırasını değil, değerin listedeki yerini okur.

  1. const renk = d3.scaleOrdinal().domain(["Ankara", "İzmir", "Bursa"]).range(schemeTableau10) ölçeği her şehri listedeki yerine göre bağlar.
  2. Çağrı sırası ne olursa olsun renk("İzmir") #f28e2c, renk("Ankara") #4e79a7, renk("Bursa") #e15759 döndürür.
  3. Listede olmayan bir kategori için .unknown("#bab0ac") eklenirse, örneğin renk("Van") bu griyi döndürür ve tanım alanı büyümez.

Son adım önemlidir: bilinmeyen değer tanımlanmazsa, yeni bir kategori ölçeğe sessizce eklenir ve bir sonraki rengi kapar. Bilinmeyen değeri griye bağlamak, VG-06'daki gri zemin düşüncesinin kodda karşılığıdır: tanımlanmamış kategori göze çarpmaz, ama kaybolmaz da.

Sayısal veri: renk haritası ve normalleştirme

Sayısal veride renk, bir renk haritasından okunur. VG-02'nin anlattığı viridis, matplotlib için tasarlanmış algısal olarak düzgün bir haritadır; D3'ün belgesi de interpolateViridis işlevini, van der Walt, Smith ve Firing'in matplotlib için tasarladığı «viridis» algısal olarak düzgün renk şemasından bir renk döndüren işlev olarak tanımlar.

Bir renk haritası 0 ile 1 arasındaki sayıları renge çevirir; verinin bu aralığa yerleştirilmesi ayrı bir adımdır. VG-05 bu adımı normalleştirme olarak tanımlamıştı.

  1. Python'da matplotlib.colormaps["viridis"] haritayı verir; cmap(0.0) #440154, cmap(1.0) #fde725 rengine karşılık gelir.
  2. Normalize(vmin=0, vmax=200) ile kurulan bir normalleştirme, 50 değerini 0,25'e yerleştirir.
  3. D3'te d3.scaleSequential(interpolateViridis).domain([0, 200]) aynı işi tek ölçekte yapar: 0 #440154, 200 #fde725 olur.

Eksik veri de bir renk kararıdır. D3'ün belgesine göre sürekli bir ölçeğin tanımsız ya da sayı olmayan girdiler için döndürdüğü bilinmeyen değer varsayılan olarak tanımsızdır; denendiğinde d3.scaleSequential(interpolateViridis).domain([0, 200]) ölçeği NaN için undefined döndürür ve hücre rengi belirlenmeden çizilir. Ölçeğe .unknown("#bab0ac") eklendiğinde aynı girdi griyi alır. Bilinmeyen değere bir gri atamak, eksik verinin bir ölçüm gibi okunmasını önler ve kategori ölçeğindeki griyle aynı düşünceyi taşır.

İki ayrı grafikte aynı renk bir anlama gelecekse, vmin ve vmax değerleri ya da D3'teki tanım alanı da sabitlenmelidir. Her grafik kendi verisinin en küçüğünü ve en büyüğünü kullanırsa, aynı sarı bir grafikte 50'yi, öbüründe 200'ü gösterebilir. Bu, kategori renklerindeki sıra sorununun sayısal karşılığıdır.

Iraksak verilerde VG-01'de tanımlanan orta nokta ayrıca sabitlenir. Değerler −2 ile 6 arasındaysa ve orta nokta sıfırsa, basit bir normalleştirme sıfırı ortaya koymaz.

  1. Python'da TwoSlopeNorm(vmin=-2, vcenter=0, vmax=6) sıfırı 0,5'e, −2'yi 0'a, 6'yı 1'e yerleştirir; 3 değeri 0,75'e düşer.
  2. D3'te d3.scaleDiverging(interpolateRdBu).domain([-2, 0, 6]) üç noktalı bir tanım alanıyla aynı işi yapar: sıfır haritanın ortasındaki açık renge (rgb(242, 239, 238)) karşılık gelir.

Ayarları tek yerde tutmak: stil dosyası

Bir projede onlarca grafik varsa, renk kararlarını her dosyaya ayrı ayrı yazmak hataya açıktır. Bir dosyada güncellenen renk öbüründe eski hâlinde kalır ve tutarlılık kimse fark etmeden bozulur. Bu yüzden kararlar tek bir yerde toplanır ve bütün grafikler oradan okur.

  1. kurum.mplstyle adlı bir dosyaya axes.prop_cycle: cycler('color', ['1f77b4', 'ff7f0e', '2ca02c']) ve image.cmap: viridis satırları yazılır.
  2. plt.style.use("kurum.mplstyle") çağrıldığında döngü bu üç renge, varsayılan harita viridis'e ayarlanır.

D3'te bunun karşılığı, ölçek nesnesini bir modülde bir kez tanımlayıp bütün grafiklerde aynı nesneyi kullanmaktır. Stil dosyası döngüyü ve haritayı ortaklaştırır; kategoriyi renge bağlayan sözlük ya da tanım alanı ise ayrıca ortak tutulmalıdır.

Örnek — ten grupları bir kategori paleti olunca

Bir veri seti, örneğin bir fondöten gamındaki tonların dağılımı, ten gruplarını kategori olarak içeriyorsa, grupları serinin dört ten rengiyle göstermek akla gelen ilk seçimdir. Bu paletin kategori paleti olarak ne kadar ayırt edilebildiğini, matplotlib'in varsayılan döngüsünün ilk dört rengiyle karşılaştırdık: her paletteki en yakın iki rengin CIEDE2000 farkını, normal görmede ve döteranopi benzetiminde hesapladık.

PaletEn yakın çift, normal görmeEn yakın çift, döteranopiL\* aralığı
Dört ten (F1C7A9, C68863, 8D5524, 4A2C1D)F1C7A9–C68863, 16,9F1C7A9–C68863, 15,621,4–83,1
Varsayılan döngünün ilk dördüturuncu–kırmızı, 26,5yeşil–kırmızı, 4,646,8–66,9

Varsayılan döngü normal görmede daha ayrık görünür, ama döteranopide yeşil ile kırmızı neredeyse birleşir; VG-07'de gördüğümüz kırmızı–yeşil çiftinin sorunu varsayılan palette de vardır. Dört ten ise renk görme eksikliğinde de ayrık kalır, çünkü aralarındaki fark büyük ölçüde açıklıktadır. Bunun bir bedeli vardır: VG-04'teki koyu-çok yanlılığı yüzünden okur, açıklığı düzenli değişen renkleri bir sıra ya da miktar olarak okumaya eğilimlidir. Ten grupları bir miktar değil, bir kategoridir; bu yüzden böyle bir grafikte grupların doğrudan etiketlenmesi ve renklerin bütün grafiklerde aynı gruba bağlı kalması, yani bir sözlük ya da tanım alanıyla sabitlenmesi gerekir. Hangi paletin seçileceği bir tasarım kararıdır; ölçülebilir olan, her paletin hangi koşulda ayrık kaldığıdır.

Sık yapılan yanlış

Yaygın yanlış"Renk haritası seçildiyse iki grafiğin renkleri karşılaştırılabilir."
Doğrusu

Harita aynı olsa bile her grafik kendi verisinin en küçük ve en büyük değerine göre normalleştirilirse aynı renk farklı değerleri gösterir; karşılaştırılacak grafiklerde normalleştirme sınırları da sabitlenmelidir.

Özet

  1. matplotlib'in renk döngüsü ve D3'ün örtük tanım alanlı kategori ölçeği renkleri karşılaşma sırasıyla dağıtır; bu yüzden aynı kategori farklı grafiklerde farklı renk alabilir.
  2. Kategori renkleri Python'da bir sözlükle, D3'te açık bir tanım alanı ve bilinmeyen değer için bir gri ile sabitlenir; sayısal verilerde renk haritasıyla birlikte normalleştirme sınırları ve ıraksak veride orta nokta da sabitlenir. Stil dosyası ya da ortak ölçek nesnesi bu kararları tek yerde tutar.
  3. Örnekte varsayılan döngünün yeşil–kırmızı çifti döteranopide ΔE00 4,6'ya inerken dört ten paleti 15,6'da kalır; ama açıklığa dayalı bir palet sıra ima eder ve doğrudan etiket gerektirir.

Kendini sına

  1. (Kolay) matplotlib'in 2.0 sürümünde varsayılan renk döngüsü ve renk haritası neye değiştirildi?
  2. (Kolay) D3'te bir kategori ölçeğinin tanım alanı verilmezse ne olur?
  3. (Orta) Kategori renklerini neden tüm grafiklerde sabitlemek gerekir?
  4. (Orta) Python'da ve D3'te kategori renkleri nasıl sabitlenir?
  5. (Zor) Aynı renk haritasını kullanan iki grafiğin renkleri neden yine de karşılaştırılamayabilir?
  6. (Zor) Örnekte dört ten paleti döteranopide neden ayrık kalır ve bu paletin bedeli nedir?

Cevaplar

  1. Renk döngüsü Vega ve d3'ün kullandığı, Tableau'da geliştirilmiş category10 paletine, varsayılan renk haritası viridis'e değiştirildi. Bkz. "matplotlib'in varsayılanları".
  2. Ölçeğe verilen her yeni değer tanım alanına örtük olarak eklenir ve aralıktaki bir sonraki rengi alır; renk, değerin kendisine değil karşılaşılma sırasına bağlı olur. Bkz. "Kategori renklerini sabitlemek: D3".
  3. Çünkü kütüphaneler renk belirtilmediğinde kategorilere renkleri karşılaştıkları sırayla dağıtır; veri farklı sırayla geldiğinde aynı kategori iki grafikte iki ayrı renk alır. Okur bir grafikte öğrendiği renk anlamını öbüründe kullanır ve yanlış okur; örneklerde Ankara bir grafikte mavi, öbüründe turuncudur. Bkz. "matplotlib'in varsayılanları".
  4. Python'da kategoriyi renge bağlayan bir sözlük kurulur ve çizimde color=renkler[sehir] ile renk açıkça verilir; D3'te ölçeğe domain ile tanım alanı açıkça verilir ve listede olmayan kategoriler için unknown ile bir gri tanımlanır. Bkz. "Kategori renklerini sabitlemek: Python" ve "Kategori renklerini sabitlemek: D3".
  5. Çünkü her grafik kendi verisinin en küçük ve en büyük değerine göre normalleştirilirse aynı renk bir grafikte 50'yi, öbüründe 200'ü gösterebilir; normalleştirme sınırları ve ıraksak veride orta nokta da sabitlenmelidir. Bkz. "Sayısal veri: renk haritası ve normalleştirme".
  6. Çünkü dört ten arasındaki fark büyük ölçüde açıklıktadır ve döteranopi açıklık farkını korur; en yakın çift 15,6'da kalır. Bedeli, açıklığı düzenli değişen renklerin koyu-çok yanlılığı yüzünden bir sıra ya da miktar gibi okunmasıdır; bu yüzden gruplar doğrudan etiketlenmeli ve renkler bütün grafiklerde sabitlenmelidir. Bkz. "Örnek".

Kaynaklar

  • Matplotlib Development Team, «Changes to the default style», matplotlib 2.0.2 belgeleri, matplotlib.org.
  • Matplotlib Development Team, «Choosing Colormaps in Matplotlib», matplotlib 3.11.2 belgeleri, matplotlib.org.
  • D3, «Ordinal scales», d3-scale belgeleri, d3js.org.
  • D3, «Sequential schemes» ve «Categorical schemes», d3-scale-chromatic belgeleri, d3js.org.

Sonraki adım

VG-09 kategori sayısı çoğaldığında ne yapılacağını soruyor: ayırt edilebilir renk sayısının sınırını, «diğer» grubunu, tek kategoriyi vurgulayıp kalanını griye çekmeyi ve küçük çoklu grafikleri anlatıyor ve on beş ülkenin verisini tek grafikte renkle ayırmak yerine ne yapılabileceğini soruyor. Sabit kategori rengi ilkesi VG-06'da, veri tipine göre palet seçimi VG-01'de ele alınmıştı.

Anlamadığın bir yer mi var?

Mentor yalnız bu dersin metnine dayanarak cevap verir. Metinde geçmeyen bir şey sorarsan uydurmaz, geçmediğini söyler.

Animasyon ve seslendirme notları

Animasyon ve seslendirme notları

Video akışı

  • 0:00–0:40 Kanca: İki çizgi grafiği yan yana; Ankara solda mavi, sağda turuncu. «Aynı kod, farklı sıra.»
  • 0:40–2:30 Hikâye: Renk döngüsü bir kuyruk gibi çizilir; gelen her seri kuyruğun başındaki rengi alır.
  • 2:30–4:00 Açıklama: Sözlük bir anahtar–renk tablosu olarak belirir; sıra değişse de şehirler renklerini korur. D3'te tanım alanı listesi.
  • 4:00–5:00 Aha anı: Tanımsız bir kategori, «Van», ölçeğe girer ve bir rengi kapar; bilinmeyen değer griye bağlanınca kenarda kalır.
  • 5:00–6:30 Sayısal veri: Viridis çubuğu; iki grafik farklı sınırlarla normalleştirilince aynı sarı iki ayrı değere karşılık gelir. Orta nokta çizgisi.
  • 6:30–7:30 Stil dosyası: Tek bir dosya, bütün grafiklere ok çizer.
  • 7:30–9:00 Gerçek dünya: Dört ten grubu bir çubuk grafiğinde; normal görme ve döteranopi benzetimi yan yana; yanında varsayılan döngünün yeşil–kırmızı çifti birleşir.
  • 9:00–9:30 Yanlış bilinen: «Kütüphane tutarlıdır» yazısının üstü çizilir.
  • 9:30–10:00 Kapanış: On beş renkli karmakarışık bir çizgi grafiği; VG-09 kodu.

Görsel notları

  • Kod parçaları ekranda eş aralıklı yazıyla, ders metnindekiyle birebir aynı gösterilir; ekran görüntüsü değil özgün dizgidir.
  • Grafikler dersteki kodla üretilir; renk değerleri metindeki çıktılarla aynıdır.
  • Ten grupları grafiği kurgusal bir veriyle çizilir; gerçek bir markanın ürün verisi kullanılmaz.
  • Döteranopi görünümü bir benzetimdir; ekranda bu not yer alır.