800100715151 Astronomide Veritabanları

Ders - 06 Veri Görselleştirmenin Temelleri

Doç. Dr. Özgür Baştürk
Ankara Üniversitesi, Astronomi ve Uzay Bilimleri Bölümü
obasturk at ankara.edu.tr
http://ozgur.astrotux.org

Veri Görselleştirme Neden Önemlidir?

Bir veri setini görselleştirme, özellikle büyük veri setlerinde i) bir bakışta farkedilemeyen detayların farkedilmesine, ii) parametreler arası ilişkilerin kurulabilmesine, iii) konuya ilişkin sorulara çabuk cevap verilebilmesine, iv) bazı konuların daha derin ve iyi anlaşılabilmesine ve v) neden-sonuç ilişkilerinin kurulabilmesine olanak sağlar.

Tablolara bakarken, araştırıcının her şeyden önce en çok ilgisini çeken öne çıkan rakamlardır. Ancak bazen insan, ilgisini çekenlere odaklanırken önemli bazı detayları gözden kaçırabilir (algıda seçicilik). İyi bir örnek için bkz.

Altı ülkenin (İspanya, Portekiz, Güney Kore, Çin, Türkiye ve Brezilya) kişi başına düşen gayrisafi milli hasılarının 1980'den bu yana 10 yıllık dönemler için değerleri örneği üzerinden görselleştirmenin nasıl faydalar sağladığı ve ne tür çıkarımlara yol açtığı aşağıda örneklenmeye çalışılmıştır.

In [1]:
import pandas as pd
import numpy as np
gsmh = {1980 : pd.Series([6113, 3335, 1711, 309, 2169, 1229], \
                              index=['Ispanya','Portekiz','Guney Kore','Cin','Turkiye','Brezilya']),
        1990: pd.Series([13650, 7941,6513,349,3747,3172], \
                              index=['Ispanya','Portekiz','Guney Kore','Cin','Turkiye','Brezilya']),
        2000 : pd.Series([14725,11536,12257,959,4219,3779], \
                              index=['Ispanya','Portekiz','Guney Kore','Cin','Turkiye','Brezilya']),
        2010 : pd.Series([30803,22581,23087,4524,10476,11298], \
                              index=['Ispanya','Portekiz','Guney Kore','Cin','Turkiye','Brezilya']),
        2020 : pd.Series([30734,23731,31246,10872,9633,9765], \
                              index=['Ispanya','Portekiz','Guney Kore','Cin','Turkiye','Brezilya']),
        2021: pd.Series([30157,24495,34994,14096,8081,8570], \
                              index=['Ispanya','Portekiz','Guney Kore','Cin','Turkiye','Brezilya']),
       }
gsmh = pd.DataFrame(gsmh)
gsmh
Out[1]:
1980 1990 2000 2010 2020 2021
Ispanya 6113 13650 14725 30803 30734 30157
Portekiz 3335 7941 11536 22581 23731 24495
Guney Kore 1711 6513 12257 23087 31246 34994
Cin 309 349 959 4524 10872 14096
Turkiye 2169 3747 4219 10476 9633 8081
Brezilya 1229 3172 3779 11298 9765 8570

Veri noktalarını doğrularla birleştirerek oluşturulan eğri grafikleri (ing. line plot) özellikle bir niceliğin zaman içerisindeki değişimini görselleştirme ve karşılaştırma açısından faydalıdır.

Bir pandas veriçerçevesi üzerinde grafik çizimi yapabilmek için plot metodu tanımlanmıştır ve pek çok grafik türü (line, scatter, box vs.) bu fonksiyonla çizdirilebilir. Fonksiyon arka planda matplotlib.pyplot fonksiyonlarını kullanır.

In [2]:
%matplotlib inline
from matplotlib import pyplot as plt
renkler = ['purple','green','blue','orange','red','yellow']
# yillara karsilik GSMH degisimini dogrudan cizdirebilmek icin
# oncelikle vericercevesinin transpozu alinmalidir.
gsmh.transpose().plot(kind="line",
                      color=renkler,
                      marker="o")
plt.grid(True)
plt.xlabel('Yillar')
plt.ylabel('GSMH')
plt.legend(loc='upper left')
plt.show()

Sosyal bilimci olmamakla birlikte ele alınan tüm ulkelerin 2000 ile 2010 arasında kişi başına düşen milli gelirlerini arttırdıkları, 1980'lerde Türkiye'nin gerisindeki Çin, Güney Kore ve Brezilya'nın Türkiye'yi geçtiği, İspanya ve Portekiz'in Avrupa Birliği üyesi ülke oluşlarını takiben ulusal gelirlerini hızla arttırdıkları ancak 2010'lar sonrası bu artışın yavaşladığı, Güney Kore'nin ise bilime yaptığı yatırımın sürekli bir artışla gelirlerini tüm bu ülkeleri geçecek duruma getirdiği görülmektedir.

Yukarıdaki gibi bir tablodansa bu grafiklere bakarak zamanla değişimi görmek ve başka ülkelerinki ile karşılaştırmak çok daha kolaydır. Bir grafik, bir tablodan veya yukarıdaki gibi bir paragraf yazadan çok daha fazlasını çok kısa daha kısa sürede, özellikle grafik yorumlamak konusunda eğitimli insanların kolayca anlayacağı şekilde anlatır.

Veri görselleştirmenin çok güzel bir örneğini alanın devlerinden Hans Rosling'in 4 dakikada 200 ülkenin 200 yıldaki gelişimi videosunda bulabilirsiniz.

Veri Görselleştirme Paketleri

İstatistiksel Bilgi Veren Görselleştirme Uygulamaları: Dağılım grafikleri (ing. scatter plots) ya da eğri uyumlama gibi uygulamaları destekleyen paketlerdir.

  • matplotlib: Python'da statik, hareketli ya da interaktif görselleştirmeler oluşturmak için kapsamlı bir kütüphanedir. John D. Hunter tarafından 2003 yılında EKG diyagramlarını görselleştirmek ve Matlab ortamındakine benzer grafikler oluşturmak için yazılmış, pek çok gönüllü programcının katkılarıyla geliştirilerek bugünkü yaygınlığını sağlayan başarımına erişmiştir.

  • seaborn: matplotlib üzerine inşa edilmiştir. Renk paletleri ve çizim estetiği veri setlerindeki özellikle istatistiksel bilgileri sunabilmek üzere geliştirilmiştir.

Grafikle Görselleştirmenin Gramerine Yönelik Uygulamalar: matplotlib arayüzünün çok ayrıntılı bulunması durumunda R programlama dilinin ggplot2 görselleştirme paketini temel alan paketler gibi uygulamalar kullanılabilir.

  • ggplot: matplotlib 'a dayanır ve ona benzer bir işlevsellik sağlar ancak farklı ve daha kolay bir arayüz sağlar.

  • altair: ggplot ile karşılaştırıldığında daha da basit bir arayüze sahiptir vejupyter not defterlerine kolayca yerleştirilebilen veya PNG olarak dışa aktarılabilen Javascript tabanlı grafikler oluşturur.

İnteraktif Görselleştirme Uygulamaları:: zoom, pan, veri noktalarını interaktif etiketleme gibi özellikler sağlayan, aynı zamanda bir web sayfasında bağımsız çalışmak için Javascript olarak dışa aktarılabilen grafik uygulamalar sunan paketlerdir.

  • bokeh: Anaconda paketinin üreticisi Continuum Analytics şirketinin görselleştirme paketidir ve özellikle internette sunmak üzere interaktif görselleştirme ve infografik uygulamaları geliştirmenizi sağlar. Kullanıcı arayüzünden veya seri veri güncellemelerinden ve stream'lerden gelen olaylara yanıt vermeyi sağlayan ayrı bir Python süreci başlatmak için bir da grafik sunucu (bokeh plot server) desteği bulunmaktadır.

  • plotly: görselleştirmelerinizi depolayabileceğiniz ve paylaşabileceğiniz bir kütüphane ve bulut hizmetidir (ücretsiz / ücretli hesapları vardır)

İnteraktif Harita Uygulamaları: renkli ve interaktif özelliklerde haritalar yaratmanıza olanak sağlarlar.

  • folium: Verileri haritaların üstünde görüntülemek için $Leaflet.js$ javascript çizim kütüphanesine bağlı HTML sayfaları oluşturur.

  • plotly: jupyter not defterlerine gömülü renk kodlu ülke / dünya haritalarını da destekler.

Üç Boyutlu (3D) Görselleştirme Uygulamaları:

  • mplot3d: matplotlib 'in 3-boyutlu görselleştirme uygulamalarına platform sağlayan paketidir.

Matplotlib Kütüphanesi

Bu derste matplotlib altyapısını kullanan ve pandas veriçerçeveleri üzerinde tanımlı plot fonksiyonu sıklıkla kullanılacaktır. Ancak grafik parametrelerini tanımlamak ve özellikleri üzerinde daha geniş kontrole sahip olabilmek için kütüphanenin diğer fonksiyonlarından da yararlanılacaktır. Bu nedenle matplotlib kütüphanesinin yapısından ve mimarisinden kısaca bahsetmekte fayda vardır. Daha geniş bilgi için matplotlib dokümantasyonun incelenmesi ve gerektiğnde dış kaynaklara başvurulması önerilir.

matplotlib, kodlama katmanı (scripting layer), grafik nesnneleri katmanı (artist layer) ve arkayüz katmanı (backend layer) adı verilen üç katmandan oluşmaktadır.

Arkayüz (Backend) Katmanı

Arkayüz, bilgisayarda grafik çizimi amaçlı daha düşük düzey, wxPython gibi araçlar veya PostScript gibi çizim dilleriyle iletişim kurarak arka plandaki işleri yerine getirir. Kütüphanenin temeli olup, en komplike işlerin yapıldığı katmandır. Üç ana bileşenden oluşur

  • FigureCanvas — matplotlib.backend_bases.FigureCanvasBase Şeklin tuvale (ing. canvas) aktarıldığı nesne ve metotlardan oluşan arabirimidir.

  • Renderer —matplotlib.backend_bases.RendererBase Çizim ve aktarım (rendering) işlemlerinin yapıldığı nsene ve metotlardan oluşan arabirimdir. FigureCanvas 'a şeklin aktarılmasından sorumludur.

  • Event — matplotlib.backend_bases.Event Klavye ve fare gibi çevre birim elemanlarından gelen girdileri alan ve yorumlayan nesne ve metotlardan oluşan arabirimdir.

Çoğu grafik çiziminde (ve bu ders boyunca) kullanıcının arkayüzle ilgilenmesine hiç gerek olmamaktadır. Ancak matplotlib altyapısına dayalı bir grafik çizim uygulaması programlanmak istendiğinde arkayüz hakimiyeti gerekecektir.

Grafik Nesneleri (Artist) Katmanı

Tıpkı bir sanatçının tuval üzerine yaptığı ince ayarlar gibi, kullanıcının şekillerin mümkün olduğunca çok özelliğini kontrol etmesine ve ince ayar yapmasına olanak sağlayan nesne ve metotlardan oluşan katmandır. Bu katman, "tuval" (ing. canvas) üzerine çizim yapmak için Renderer arabirimini kullanan Artist adlı bir ana nesneden oluşur. Birden fazla şekil ya da eksen kullanılırken, her bir alt grafik (subplot) bir Artist nesnesine atandığından hangisinin aktif olduğu konusunda bir karışıklık oluşulmasına önüne geçilmiş olunur. Bu ana nesne ve altındaki grafik nesnelerinin yönetimine dayalı olduğu için nesne yönelimli grafik çizimi olarak da adlandırılır. Bir matplotlib figürünün üzerindeki başlık (title, sembol, çizgi ve eksen gibi her bir özellik bir nesne ile tanımlanır.

İki tür Artist nesnesi vardır.

  • Primitive: Line2D, Rectangle, Circle ve Text gibi temel tür nseneler,

  • Composite: Axis, Ticks, Figure gibi kompozit nesneler. Bu nesneler temel nesneler ya da diğer kompozit nesnelerin bileşiminden oluşurlar.

Bir üst katman olan kodlama katmanına kıyasla daha fazla özelleştirme yapma olanağı sağlar ve gelişmiş grafikler üretmek üzere grafik nesneleri üzerinde tam kontrole ihtiyaç duyulduuğu durumlar için daha uygundur. Grafiklerin üretileceği bir web uygulaması ya da kullanıcı arayüzü geliştirmek için de sıklıkla başvurulur.

Grafik nesneleri katmanı hakkında daha fazla bilgi için maplotlib Artist Tutorial dokümantasyonunu incelemeniz önerilir.

Örnek: $\mu = 0$, $\sigma = 1$ ile tanımlanan standart normal dağılımdan rastgele seçilmiş 10000 örnekten oluşan normal dağılım örnekleminin grafik nesneleri katmanı düzeyinde histogramının çizimine bir örnek aşağıdaki kodla verilmiştir.

In [3]:
# Arkayuz (backend) nesnesi tuvale (canvas) sekil cizdirmek uzere 
# Grafik nesneleri katmani nesnesi FigureCanvas import edilir
# Arkayuzden import edilen FigureCanvasAgg "anti grain geometry" adli kutuphanenin
# tuval nesnesi olup, estetik olarak etkileyici sekiller icin gerekli ayarlara sahiptir
# 'agg' stands for 'anti grain geometry' which is a high-performance library that produces nice images.
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas

# Figure nesnnesi import edilir
from matplotlib.figure import Figure

# rastgele dagilimi olusturmak ve sayi dizilerinin kontrolu icin numpy
import numpy as np

fig = Figure()
canvas = FigureCanvas(fig)

# mu = 0, sigma = 1 standart normal dagilimdan 10000 buyukugundeki orneklem
x = np.random.randn(10000)

# figure nesnesine otomatik olarak eklenen axes Artist nesnesinin olusturulmasi
# 1 satir 1 sutunda 1. seklin eksen nesnesi
ax = fig.add_subplot(111)

# 50 kutucuktan olusan histogramin cizdirilmesi
ax.hist(x, bins=50)

# Baslik ve eksen etiketleri
ax.set_title('Standart Normal Dagilimdan Rastgele Secilmis 10000 Sayinin Dagilimi')
ax.set_xlabel('x')
ax.set_ylabel('N')
fig.savefig('normal_daigilim.png')

Kodlama (Scripting) Katmanı

Verisini çok fazla teknik detayla ilgilenmeden analiz etmek isteyenler için geliştirilmiş olan kodlama katmanı matplotlib.pyplot nesneleri aracılığı ile sağlanır.

matplotlib mimarisinin en üst katmanıdır ve MATLAB betikleri şeklinde çalışmasını sağlamak için tasarlanmıştır. Kullanımı en kolay ve dolayısı ile en yaygın katmandır. Grafik Nesneleri Katmanı (Artist layer) nesne yönelimli grafik çizimi katmanı olarak adlandırıldığından, programcılıktaki yapıya benzer şekilde yapısal çizim katmanı (ing. procedural plotting) olarak da adlandırılır. Bir FigureCanvas nesnesinin oluşturulup Figure grafik nesnesiyle bağlanmasını otomatik olarak üstlenen matplotlib.pyplot paketi fonksiyon ve nesneleri üzerine kurulu olduğu için bu katman da özünde nesne yönelimlidir ancak kullanıcının bunun farkında olması gerekmez!

Örnek: Grafik nesneleri katmanına örnek olarak verilen standart normal dağılımdan rastgele seçilen 10000 sayıdan oluşan örneklemin histogramının kodlama katmanında çizimi aşağıdaki kodla verilmiştir.

In [4]:
%matplotlib inline
# FigureCanvas nesnesinin otomatik olarak import edilisi
import matplotlib.pyplot as plt
# standart normal dagilim ve dizi islemleri icin numpy
import numpy as np

# standart normal dagilimin olusturulmasi
np.random.seed(123)
x = np.random.randn(10000)

# Histogramin cizimi
plt.hist(x, 50)
# Baslik ve eksen etiketleri
plt.title('Standart Normal Dagilimdan Rastgele Secilmis 10000 Sayinin Dagilimi')
plt.xlabel('x')
plt.ylabel('N')
#fig.savefig('normal_daigilim.png')
plt.show()

matplotib hakkında daha fazla bilgi, örnek ve tutorial formatındaki dokümanlar için dokümantasyon sayfasını, özellikle mimari hakkında daha detaylı bilgi için ise kütüphaneyi geliştiren John Hunter ve Michael Droettboom'ın yazısını okumakta fayda vardır.

Matplotlib ve Jupyter Defterleri

jupyter notebook defterlerinde matplotlib grafiklerini görüntülemek için farklı modlar bulunmaktadır. Bu modlar jupyter sihirli kelimeleri (magic words) kullanılarak aktif hale getirilebilir.

  • %matplotlib inline interaktif kullanım araçları olmaksızın grafiğin ekrana getirilmesini sağlar.

  • %matplotlib notebook grafikler üzerinde zoom, pan gibi interaktif işlevlerin uygulanabilmesine olanak sağlayan moddur. Uyarı: Oluşturulan grafiğin sağ üstünde yer alan ve etkileşimi sonlandıran butonun tıklanmaması durumunda bir sonraki grafik interaktif olarak çalışmayabilir ve hata verebilir. Bu tür hataları önlemek için matplotlib.pyplot paketinin modun jupyter sihirli kelimesi ile (iki kez) aktif hale getirilmesi sonrası (daha önce edilmemişse) import edilmesi gerekebilmektedir.

Aslında bu jupyter "sihirli kelimeleri" matplotlib arkayüzünü (backend) değiştirmektedir. Arkayüzler hakkında daha fazla bilgi için bkz.. %matplotlib widget, %matplotlib ipympl ile aktif hale getirilebilecek diğer arkayüzler ve mpld3 gibi interaktif kullanım sağlayan başka kütüphaneler de bulunmaktadır. Ancak en sık kullanılan arkayüzler (ya da modlar) inline ve notebook burada örneklenmiştir.

In [48]:
%matplotlib notebook
%matplotlib notebook
import matplotlib.pyplot as plt
# Histogramin cizimi
plt.hist(x, 25)
# Baslik ve eksen etiketleri
plt.title('Standart Normal Dagilim')
plt.xlabel('x')
plt.ylabel('N')
plt.show()

Sistemde yüklü matplotlib versiyonunu ve hazır grafik stillerini görmek için

In [6]:
import matplotlib as mpl
mpl.__version__
Out[6]:
'3.3.4'
In [7]:
print(plt.style.available)
['Solarize_Light2', '_classic_test_patch', 'bmh', 'classic', 'dark_background', 'fast', 'fivethirtyeight', 'ggplot', 'grayscale', 'seaborn', 'seaborn-bright', 'seaborn-colorblind', 'seaborn-dark', 'seaborn-dark-palette', 'seaborn-darkgrid', 'seaborn-deep', 'seaborn-muted', 'seaborn-notebook', 'seaborn-paper', 'seaborn-pastel', 'seaborn-poster', 'seaborn-talk', 'seaborn-ticks', 'seaborn-white', 'seaborn-whitegrid', 'tableau-colorblind10']

Veri Görselleştirme Türleri

Eğri Grafikleri

Eğri grafiği veya çizgi grafiği (ing. line plot), veri noktalarının doğru parçalarıyla birbirine bağlandıkları temel bir grafik türüdür. Verinin içinde yer alan belirli bir zaman aralığındaki trendlerin görselleştirme sonucu belirlenebilmesi ve farklı gruplardaki trendlerin karşılaştırılması için uygun bir grafik türüdür.

Örnek: Keşif Tekniklerinin Performanslarının Zamanla Değişimi

Örnek olarak exoplanet.eu kataloğundaki verileri keşif tekniklerine göre grupladıktan her bir teknikle yapılan keşif sayılarıının zamanla değişimi incelenmek ve karşılaştırılmak isteniyor olsun.

Bu amaçla öncelikle verinin görselleştirme için hazırlanması gerekir.

In [8]:
%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
exoeu = pd.read_csv("veri/exoplanet.eu_catalog_20220427.csv")
exoeu.columns
Out[8]:
Index(['# name', 'planet_status', 'mass', 'mass_error_min', 'mass_error_max',
       'mass_sini', 'mass_sini_error_min', 'mass_sini_error_max', 'radius',
       'radius_error_min', 'radius_error_max', 'orbital_period',
       'orbital_period_error_min', 'orbital_period_error_max',
       'semi_major_axis', 'semi_major_axis_error_min',
       'semi_major_axis_error_max', 'eccentricity', 'eccentricity_error_min',
       'eccentricity_error_max', 'inclination', 'inclination_error_min',
       'inclination_error_max', 'angular_distance', 'discovered', 'updated',
       'omega', 'omega_error_min', 'omega_error_max', 'tperi',
       'tperi_error_min', 'tperi_error_max', 'tconj', 'tconj_error_min',
       'tconj_error_max', 'tzero_tr', 'tzero_tr_error_min',
       'tzero_tr_error_max', 'tzero_tr_sec', 'tzero_tr_sec_error_min',
       'tzero_tr_sec_error_max', 'lambda_angle', 'lambda_angle_error_min',
       'lambda_angle_error_max', 'impact_parameter',
       'impact_parameter_error_min', 'impact_parameter_error_max', 'tzero_vr',
       'tzero_vr_error_min', 'tzero_vr_error_max', 'k', 'k_error_min',
       'k_error_max', 'temp_calculated', 'temp_calculated_error_min',
       'temp_calculated_error_max', 'temp_measured', 'hot_point_lon',
       'geometric_albedo', 'geometric_albedo_error_min',
       'geometric_albedo_error_max', 'log_g', 'publication', 'detection_type',
       'mass_detection_type', 'radius_detection_type', 'alternate_names',
       'molecules', 'star_name', 'ra', 'dec', 'mag_v', 'mag_i', 'mag_j',
       'mag_h', 'mag_k', 'star_distance', 'star_distance_error_min',
       'star_distance_error_max', 'star_metallicity',
       'star_metallicity_error_min', 'star_metallicity_error_max', 'star_mass',
       'star_mass_error_min', 'star_mass_error_max', 'star_radius',
       'star_radius_error_min', 'star_radius_error_max', 'star_sp_type',
       'star_age', 'star_age_error_min', 'star_age_error_max', 'star_teff',
       'star_teff_error_min', 'star_teff_error_max', 'star_detected_disc',
       'star_magnetic_field', 'star_alternate_names'],
      dtype='object')

Ötegezegenlerin keşif yöntemleri detection_type, tarihleri ise discovered anahtarında bulunmaktadır. Sadece bu bilgilerle ilgilenildği için onları kullanarak gruplamalar ve veriçerçeveleri oluşturmak iyi bir fikir olacaktır.

In [9]:
exoeu.groupby('discovered')['detection_type'].describe()
Out[9]:
count unique top freq
discovered
1988.0 1 1 Timing 1
1992.0 3 1 Timing 3
1995.0 3 2 Imaging 2
1996.0 7 2 Radial Velocity 6
1998.0 8 2 Radial Velocity 7
1999.0 15 3 Radial Velocity 11
2000.0 24 3 Radial Velocity 19
2001.0 15 3 Radial Velocity 13
2002.0 33 5 Radial Velocity 29
2003.0 26 3 Radial Velocity 24
2004.0 35 4 Radial Velocity 23
2005.0 35 5 Radial Velocity 26
2006.0 39 4 Radial Velocity 27
2007.0 61 5 Radial Velocity 37
2008.0 70 7 Radial Velocity 32
2009.0 91 5 Radial Velocity 66
2010.0 132 7 Radial Velocity 60
2011.0 208 7 Primary Transit 96
2012.0 145 7 Primary Transit 87
2013.0 180 7 Primary Transit 111
2014.0 872 6 Primary Transit 790
2015.0 170 6 Primary Transit 108
2016.0 1538 8 Primary Transit 1445
2017.0 177 6 Primary Transit 92
2018.0 356 6 Primary Transit 270
2019.0 208 8 Primary Transit 105
2020.0 245 8 Primary Transit 165
2021.0 209 7 Primary Transit 88
2022.0 101 5 Primary Transit 40

Görüldüğü gibi keşif sayılarını 2009'a kadar dikine hız domine ederken, Kepler Uzay Teleskobu'nun gözlemlere başlayarak geçiş yöntemiyle gezegen keşfetmeye başlamasıyla birlikte geçiş yöntemi 2009 sonrasını domine etmiştir.

Tüm keşif yöntemlerinin toplam keşif sayılarına bakıldığında bu iki yöntemle diğer tüm yöntemlere göre daha fazla sayıda keşif yapıldığı açıktır. Bu nedenle eğri grafiği üzerinde bir karşılaştırmayı öncelikle sadece bu iki yöntemi dikkate alarak yapmak faydalı olacaktır.

In [10]:
exoeu.groupby("detection_type")['# name'].count()
Out[10]:
detection_type
Astrometry           15
Default              28
Imaging             189
Microlensing        192
Primary Transit    3523
Radial Velocity     996
TTV                  24
Timing               47
Name: # name, dtype: int64
In [11]:
transits = exoeu[exoeu['detection_type'] == 'Primary Transit']
transits.groupby('discovered').count()['# name'].plot(kind="line",
                                                    label="Gecis")
radvel = exoeu[exoeu['detection_type'] == 'Radial Velocity']
radvel.groupby('discovered').count()['# name'].plot(kind="line",
                                                       label="Dikine Hiz")

# Kepler'in gozlemlere basladigi yili isaretlemek iyi bir fikir olacaktir
plt.annotate("Kepler",
            xy=(2009, 70), xycoords='data',
            xytext=(2009, 150), textcoords='data',
            arrowprops=dict(arrowstyle="->",
                            connectionstyle="arc3"),
            )

plt.yscale("log")
plt.xlabel("Yil")
plt.ylabel("Kesif Sayisi")
plt.legend(loc="best")
plt.show()

y-ekseninin logaritmik ölçekte çizdirilmesinin nedeni, geçişle keşiflerin bazı yıllarda çok yükske sayılara ulaşmalarıdır. Bu yıllar Kepler verisinden en çok gezegenin keşfedildiği yıllardır.

Benzer bir grafik keşif sayıları yakın Kütleçekim Mercekleme ve Doğrudan Görüntüleme teknikleri için de yapılabilir. Bu kez y-eksenini logaritmik çizdirmeye de ihtiyaç duyulmayacaktır.

In [12]:
microlensing = exoeu[exoeu['detection_type'] == 'Microlensing']
microlensing.groupby('discovered').count()['# name'].plot(kind="line",
                                                          color="m",
                                                    label="Kutlecekim Mercekleme")
imaging = exoeu[exoeu['detection_type'] == 'Imaging']
imaging.groupby('discovered').count()['# name'].plot(kind="line",
                                                     color="g",
                                                       label="Dogrudan Goruntuleme")
plt.xlabel("Yil")
plt.ylabel("Kesif Sayisi")
plt.legend(loc="best")
plt.show()

Doğrudan görüntülemeyle keşiflerin 2020 sonrası büyük bir ivmeyle arttığı görülmektedir. 2022 yılı sonunda bu grafiğin ne şekilde değiştiğini incelemek ilginç olacaktır. 2027 Mayıs'ında uzaya gönderilmesi planlanan Nancy Grace Roman Teleskobu'yla alınan verilerin inclenmesi sonrası bu grafiğin y-eksenini de logaritmik ölçekte çizdirmek gerekebilecektir.

Son olarak toplam keşif sayılarının zamanla değişimine bakmak istenebilir.

In [13]:
exoeu.groupby('discovered').count()['# name'].plot(kind="line", label="Tum Yontemler", color="r")
plt.yscale("log")
# Kepler'in gozlemlere basladigi yil
plt.annotate("Kepler",
            xy=(2009, 100), xycoords='data',
            xytext=(2007, 250), textcoords='data',
            arrowprops=dict(arrowstyle="->",
                            connectionstyle="arc3"),
            )
# TESS'in gozlemlere basladigi yil
plt.annotate("TESS",
            xy=(2018, 350), xycoords='data',
            xytext=(2018, 600), textcoords='data',
            arrowprops=dict(arrowstyle="->",
                            connectionstyle="arc3"),
            )
plt.xlabel("Zaman")
plt.ylabel("Kesif Sayisi")
plt.legend(loc="best")
plt.show()

2020 sonrası bu grafikte yeni bir sıçrama beklemek mümkündür! 2022 yılında gezegen keşiflerinin yapılmış olduğu, ancak henüz 4 aydan kısa bir süre geçmiş olduğu değerlendirilmelidir.

Alan Grafikleri

Alan grafikleri, özelikle aralarında ast-üst ilişkisi bulunan değişkenlerin çoğu durumda zamanla değişimlerinin kümülatif olarak gösterildiği grafiklerdir.

Örnek olarak geçişle keşiflerin tüm keşiflerin ne kadarını oluşturduğunu ve göreli bu durumun zamanla nasıl değiştiği eğri grafiklerinin altındaki alanlar doldurularak alan grafiğiyle anlatılabilir.

In [14]:
plt.figure(figsize=(12,6))
exoeu.groupby('discovered').count()['# name'].plot(kind="area", 
                                                   stacked=False,
                                                   alpha=0.5,
                                                   label="Tum Yontemler")
transits.groupby('discovered').count()['# name'].plot(kind="area", 
                                                   stacked=False,
                                                      alpha=0.5,
                                                   label="Gecis Yontemi")
radvel.groupby('discovered').count()['# name'].plot(kind="area", 
                                                   stacked=True,
                                                    alpha=0.5,
                                                   label="Dikine Hiz")
#plt.yscale("log")
# Kepler'in gozlemlere basladigi yil
plt.annotate("Kepler",
            xy=(2009, 100), xycoords='data',
            xytext=(2007, 250), textcoords='data',
            arrowprops=dict(arrowstyle="->",
                            connectionstyle="arc3"),
            )
# TESS'in gozlemlere basladigi yil
plt.annotate("TESS",
            xy=(2018, 350), xycoords='data',
            xytext=(2018, 600), textcoords='data',
            arrowprops=dict(arrowstyle="->",
                            connectionstyle="arc3"),
            )
plt.legend(loc="upper left")
plt.show()

Bu grafiğe bakarak toplam keşiflerde 2013 ve 2016 yıllarında yaşanan artışların geçiş yöntemi, 2002 civarındaki artışın ise dikine hız yöntemi kaynaklı olduğunu söylemek mümkündür.

Histogramlar

Histogramlar, sayısal verilerin frekans dağılımlarını temsil etmek için kullanılır. x ekseni sınırları belli kutucuklara (bin) bölünerek, her veri noktası değeri itibarı ile uç noktaları arasında bulundğu kutucuğa atanır. Her kutunun y-ekseni değeri o kutudaki verilerin sayısı (frekans) ya da olasılık kütle / yoğunluk fonksiyonu değeridir. Kutu boyutları görselleştirmenin etksini artırmak ve bir aralığı ön plana çıkarmak üzere değiştirilebilir.

Örnek: Geçiş Yapan Ötegezegenlerin Yarıçap Dağılımı

Daha önce koşullu indeksleme yöntemiyle oluşturulan transits veriçerçevesinde gezegen yarıçapını gösteren radius parametresinin dağılımı örnek olarak incelenebilir. Geçiş yöntemi, yıldız yarıçapının düşük ve yüksek çözünürlüklü tayflar, tayfsal enerji dağılımı ve yıldız evrim modellerinden belirlenebilmesi durumunda gezegen yarıçapını doğrudan verir. Bu nedenle veriçerçevesinin sadece geçiş yapan gezegenlere sınırlanması durumunda bu gezegenlerin hepsinin yarıçap değerinin belirlenmiş olması gerekir. Ancak bundan emin olunamayacağı için öncelikle bir kontrol etmekte fayda vardır.

In [15]:
transits[pd.isna(transits['radius'])]['# name']
Out[15]:
12          1SWASP J1407 b
86                38 Vir b
424             HAT-P-44 c
427             HAT-P-46 c
558             HD 10442 b
1146            HD 75784 b
1147            HD 75784 c
1324               J1433 b
1745         KIC 9413313 b
1801             KOI-142 c
2506         Kepler-1520 b
2688    Kepler-1661 (AB) b
4500     SDSS J1411+2009 b
4582             TOI-203 b
4655             TOI-717 b
4763            WASP-138 b
4889             WASP-81 c
4911         WD 1032+011 b
4912         WD 1145+017 b
Name: # name, dtype: object

Görüldüğü üzere 19 gezegenin yarıçapları exoplanet.eu veritabanında yer almamaktadır. Bu gezegenlerin yarıçapları NASA Exoplanet Archive gibi diğer veritabanlarında araştırılabileceği gibi literatürde bu gezegenlere ilişkin yayınlarda bulunup eklenebilir de. Ancak yeterli sayıda örnek olduğu için bu gezegenler ilgili verçeçevesiden çıkarılarak devam edilebilir.

In [16]:
transits_rad = transits.dropna(subset=['radius'])

numpy.histogram fonksiyonu matplotlib.pyplot.histogram gibi veriyi aksi söylenmedikçe 10 kutucuğa ayırarak bu kutucukların sınırlarını ve sayılarını döndürür. Öncelikle histogramın bu parametrelerini listeledikten sonra dağılımın grafiğine bakmakta fayda vardır.

In [17]:
transits_rad['radius']
Out[17]:
37      1.57000
38      1.57000
57      1.30000
97      0.17370
113     1.02000
         ...   
4962    0.54000
4963    0.44000
4964    0.68000
4965    0.49000
4999    0.16719
Name: radius, Length: 3504, dtype: float64
In [18]:
# np.histogram returns 2 values
sayi,kutu_sinirlari = np.histogram(transits_rad['radius'])

print(sayi) # herbir kutuya dusen gezegen sayisi
print(kutu_sinirlari) # kutularin (binlerin) sinirlari
[2586  249  131  275  188   59   14    0    0    2]
[0.02543  0.328887 0.632344 0.935801 1.239258 1.542715 1.846172 2.149629
 2.453086 2.756543 3.06    ]
In [19]:
transits_rad['radius'].plot(kind='hist', figsize=(8, 5))

plt.title('Gecis Yapan Gezegenlerin Yaricap Histogrami')
plt.ylabel('N')
plt.xlabel("Yaricap ($R_{jup}$)")

plt.show()

Özellikle $[0.0-0.1]$ aralığındaki yığılma bu histogramın yorumlanmasını güçleştirmektedir. Bu nedenle bu veriyi ikiye bölmekte fayda var: $R \le 0.4 R_{jup}$ ve $R > 0.4 R_{jup}$ gibi küçük ve büyük gezegenleri birbirinden ayıran bir gruplama faydalı olabilir. Ayrıca küçük gezegenler için Jüpiter yarıçapı yerine Dünya yarıçapını kullanmak daha faydalı olacaktır. Bu amaçla astropy.constants öznitelikleri arasında yer alan R_earth ve R_jup değerlerinden faydalanılabilir.

In [20]:
from astropy import constants as const
R_earth_jup = const.R_jup / const.R_earth
transits_rad['Rearth'] = transits['radius']*R_earth_jup 
/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:3: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  This is separate from the ipykernel package so we can avoid doing imports until
In [21]:
kucukgez = transits_rad[transits_rad['radius'] <= 0.4]
buyukgez = transits_rad[transits_rad['radius'] > 0.4]
In [22]:
kucukgez['Rearth'].plot(kind='hist', figsize=(8, 5))

plt.title('Gecis Yapan Kucuk Gezegenlerin Yaricap Histogrami')
plt.ylabel('N')
plt.xlabel("Yaricap ($R_{\oplus}$)")

plt.show()

Bu histogram biraz daha sınırlanıp ($0.5 - 4.0 R_{\oplus}$), kutucuk sayısı arttırıldığında (20) küçük gezegenlerin birbiriyle kesişen biri $1.3 R_{\oplus}$, diğeri $2.2 R_{\oplus}$ civarında maksimuma ulaşan iki ayrı popülasyondan oluştukları görülmektedir. Gezegen sayısının görece az olduğu ve en "dip" noktası $1.8 R_{\oplus}$ civarında olan bu aralık literatürde Yarıçap Vadisi (ing. radius valley, Radius gap, Fulton gap) olarak bilinmektedir. Bu "vadinin" sol tarafında karasal gezegenler (süper-Dünyalar ve daha küçük gezegenler), sağ tarafında ise bir gaz zarfa sahip gezegenlerin (mini-Neptünler ve daha büyük gezegenler) bulunmaktadır. Bu ayrımın başlangıçta ince atmosfere sahip gezegenlerin genç-yıldızlarının ilk 100 milyon içinde enerjik X-ışın ve morötesi ışınlarıyla atmosferlerini tamamen kaybedip karasal birer çekirdek olarak kalırken, daha kalın atmosfere sahip olanların atmosferlerinin bir kısmını koruyabildikleri düşünülmektedir (Owen ve Wu 2017). Alternatif bir açıklama çekirdeğin çok sıcak olduğu ilk zamanlarda da atmosferi kaçırabileceği üzerine kurulmuştur (Ginzburg vd. 2017). Hirano ve Dai (2017) tarafından bu iki açıklama üzerine yapılan bir araştırma için bkz.. Her ne kadar ilk bulunduğunda bu aralık bir "boşluk" olarak isimlendirilmişse de sonradan bu aralıkta bulunan gezegenlerle birlikte giderek bir "vadiye" dönüştüğü görülmüştür. Ancak yine de bu aralık iki ayrı gezegen popülasyonunu birbirinden ayırıyor gibi görünmektedir.

In [23]:
radvalley = kucukgez[(kucukgez['Rearth'] > 0.5) & (kucukgez['Rearth'] < 4.0)]
radvalley['Rearth'].plot(kind='hist', bins=20, figsize=(8, 5))
plt.axvline(x=1.8, ls="--", color="red")
# TESS'in gozlemlere basladigi yil
plt.annotate("Yaricap Vadisi $\sim 1.8 R_{\oplus}$",
            xy=(1.8, 175), xycoords='data',
            xytext=(1.65, 30), textcoords='data',rotation=90,
            color="red"
            )
plt.title('Gecis Yapan Karasal Gezegenlerin Yaricap Histogrami')
plt.ylabel('N')
plt.xlabel("Yaricap ($R_{\oplus}$)")
plt.show()

Son olarak geçiş yöntemiyle keşfedilmiş dev gezegenlerin yarıçap dağılımı aşağıdaki histogramla verilmiştir.

In [24]:
buyukgez['radius'].plot(kind='hist', bins=25, figsize=(8, 5))

plt.title('Gecis Yapan Buyuk Gezegenlerin Yaricap Histogrami')
plt.ylabel('N')
plt.xlabel("Yaricap ($R_{\oplus}$)")

plt.show()

Bu dağılımda da $0.75 R_{jup}$ civarında bir başka vadi görmek mümkündür. Ancak bu vadi kısa yörünge dönemli ($P < 2.2$ gün) gezegenlerin yörünge dönemlerine karşılık kütleleri çizdirildiğinde kendisini çok daha iyi ortaya koyan Jüpiter-altı cisim çölü (ing. sub-Jovian desert) ya da sıcak-Neptün çölü olarak bilinen parametre uzayından kaynaklanmaktadır.. Bu grafik saçılma grafikleri konusunda örnek olarak verilecektir.

Çubuk (Sütun) Grafikleri

Çubuk (sütün) grafikleri, özellikle kategorik veride her bir kategorinin ya da özelliğin gözlenme sıklığını karşılaştırmak için kullanılır. maptlotlib de bir çubuk grafiği yatay (barh) ya da daha sıklıkla dikey (bar) çubuklar (sütunlar) kullanılarak iki farklı yapıda oluşturulabilir.

Örnek: Keşif Yöntemlerinin Birbirleri İle Karşılaştırılması

exoplanet.eu veritabanındaki ötegezegenlerin her bir keşif yöntemiyle ne kadarının keşfedildiğni karşılaştırarak performanslarını görselleştirmek için çubuk grafiklerinden yararlanılabilir.

In [25]:
yontemler = exoeu.groupby("detection_type")['detection_type'].count()
yontemler
Out[25]:
detection_type
Astrometry           15
Default              28
Imaging             189
Microlensing        192
Primary Transit    3523
Radial Velocity     996
TTV                  24
Timing               47
Name: detection_type, dtype: int64
In [26]:
plt.figure(figsize=(10,5))
renkler = ["purple","violet","blue","green","yellow","orange","red","brown"]
yontemler.plot(kind="bar", color=renkler)
plt.title("Kesif Yontemlerinin Performansi")
plt.xlabel("Yontem")
plt.ylabel("Kesif Sayisi")
plt.show()

Bir matplotlib stili de kullanarak bu grafiği yatay bir çubuk grafiği ile keşifleri performanslarına göre sıralayarak ve yüzde kaçının o yöntemle yapıldığını da çubukların üzerine yazarak görselleştirmek daha bilgi verici olabilir.

In [27]:
import matplotlib as mpl
mpl.style.use('ggplot')  # ggplot-stili
plt.figure(figsize=(10,5))
yontemler.sort_values().plot(kind="barh", color="red")
for i,sayi in enumerate(yontemler.sort_values()): 
    label = "%{:.2f}".format(sayi/exoeu.shape[0]*100)
    # place text at the end of bar (subtracting 47000 from x, and 0.1 from y to make it fit within the bar)
    plt.annotate(label, xy=(sayi, i-0.1), color='black')
plt.title("Kesif Yontemlerinin Performansi")
plt.xlabel("Kesif Sayisi")
plt.ylabel("Yontem")
plt.xlim((0,4000))
plt.show()

Pasta Grafikleri

Bir "pasta grafiği", bir daireyi (veya pastayı) orantılı dilimlere bölerek kategoriler arası sayısal oranları karşılaştırmalı olarak görselleştiren dairesel bir grafiktir. Medyada yaygın olarak kullanıldığı iyi bilinen bir tür olan pasta grafikleri matplotlib de kind=pie parametresi çizdirilir.

Bir önceki örnekte verilen ötegezegen keşif yöntemleri arası performans karşılaştırmasını bir de pasta grafiği ile görselleştirerek yapmak faydalı olacaktır.

In [28]:
# yine yontemleri basarisina gore siralamak iyi bir fikirdir
yontemler.sort_values().plot(kind='pie',
               figsize=(12, 8),
               autopct='%%%1.2f', # yuzde isaretini kullan
               startangle=90,     # 90 dereceden baslayip terse git
               shadow=True,       # add shadow 
              )
# y-ekseni gosterme
plt.ylabel(None)
plt.show()

Görüldüğü gibi bazı yöntemlerde az sayıda keşif olduğu için birbirleriyle karışabilmektedir. Bunu önlemek için bir miktar görselleştirme iyileştirmesine ihtiyaç duyulur.

In [29]:
rengler = ['gold', 'yellowgreen', 'lightcoral', 'lightskyblue', 'lightgreen', 'pink', 'turquoise', 'cyan']
kenarlik = [0.25, 0.3, 0.1, 0.1, 0.1, 0.1, 0.15, 0.2] # ortadan uzaklastirma miktarlari

yontemler.plot(kind='pie',
                            figsize=(15, 9),
                            startangle=90,    
                            shadow=True,       
                            labels=None,
                            colors=renkler,  # renklendir
                            explode=kenarlik # 'ortadan verilen miktar kadar uzaklastir
                            )

# basligi biraz yukari al
plt.title('Kesif Yontemlerinin Performansi', y=1.05) 

plt.ylabel(None)

#plt.axis('equal') 

# legend ekle
plt.legend(labels=yontemler.index, loc='lower left') 

plt.show()

Kutu Diyagramları

Kutu diyagramları (ing. box plots) Bütün veriyi dört çeyreğe ayırarak ve ortaya ortanca değeri (medyan) getirerek bir dağılımın hem görselleştirilmesine hem de veri setindeki aykırı noktaların görülebilmesine (ve gerektiğinde ayıklanabilmesine) olanak veren grafiklerdir. İlk çeyreğin sonunu gösteren Q1 değeri ile son çeyreğin başını gösteren Q3 arasındaki uzaklık, çeyrekler arası uzaklık (ing. Inter-Quartile Range, IQR) olarak tanımlanır. Kutu diyagramının her iki taraftan sınırı Q1 ve Q3'e, 1.5 x IQR kadar uzaklıktadır ve buralar bir çizgi ile (whisker) gösterilir.

Örnek: Dışmerkezlilik Aralıkları

Farklı keşif yöntemleri farklı dış merkezlilikteki gezegenlerin keşfedilmesine daha duyarlıdır. Örneğin geçiş yöntemi yıldızına yakın ve büyük gezegenleri keşfetmeye daha duyarl olduğundan aynı zamanda bu özellikleri nedeniyle yıldızıyla aralarındaki kuvvetli tedirginlik etkileşmeleri sonucu daha çembersel yörüngelere zorlanmış gezegenleri keşfetmek konusunda daha başarılıdır. Doğrudan görüntüleme yönteminde ise yöntemin teknik sınırları nedeniyle yıldızına uzak ve genç gezegenlerin keşfedilmesi daha kolaydır. Bu gezegenlerin yörünge dış merkezlilikleri de bu nedenle daha büyük olabilmektedir. Keşif yöntemlerine göre bu aralıklara bakmak ve karşılaştırmak çok iyi bir fikir olacaktır.

Öncelikle verileri analiz için tekrar hazırlamak gerekecektir.

In [30]:
# Daha once bu veri islendigi icin tekrar orjinal halini elde etmek gerekebilir
# Istatistiksel olarak anlamli sayida ornek barindiran 4 kesif yontemi
exoeu_ecc = exoeu.dropna(subset=['eccentricity'])
transits_ecc = exoeu_ecc[exoeu_ecc['detection_type'] == "Primary Transit"]
radvel_ecc = exoeu_ecc[exoeu_ecc['detection_type'] == "Radial Velocity"]
imaging_ecc = exoeu_ecc[(exoeu_ecc['detection_type'] == "Imaging") & exoeu_ecc['eccentricity'] < 1]
lensing_ecc = exoeu_ecc[exoeu_ecc['detection_type'] == "Microlensing"]
In [31]:
fig, ax = plt.subplots(1, 4)
ax[0].boxplot(transits_ecc['eccentricity'])
ax[0].set_xlabel("Transits")
ax[0].set_ylim((-0.01,1.0))
ax[1].boxplot(radvel_ecc['eccentricity'])
ax[1].set_xlabel("Rad. Vel.")
ax[1].set_ylim((-0.01,1.0))
ax[2].boxplot(imaging_ecc['eccentricity'])
ax[2].set_xlabel("Imaging")
ax[2].set_ylim((-0.01,1.0))
ax[3].boxplot(lensing_ecc['eccentricity'])
ax[3].set_xlabel("Lensing")
ax[3].set_ylim((-0.01,1.0))
plt.show()

Tüm kutu diyagramlarını tek bir grafik üzerinde göstermek için veriyi bir liste içine almak gerekir. Zira numpy dizilerinin ve pandas serilerinin bu şekilde birleştirilebilmesi için aynı uzunlukta olmaları gereklidir. Oysa listeler için böyle bir zorunluluk bulunmamaktadır.

In [32]:
eccdist = [transits_ecc['eccentricity'],radvel_ecc['eccentricity'],
           imaging_ecc['eccentricity'],lensing_ecc['eccentricity']]
etiketler=["Transits","Rad.Vel.","Imaging","Lensing"]
plt.boxplot(eccdist)
plt.xticks([1,2,3,4], etiketler, rotation='vertical')
plt.show()

Grafik hemen hangi yöntemin ortancısının hangi yörünge dışmerkezliliğinde olduğunu göstermekte, sırasıyla kütleçekimsel mercek, dikine hız ve doğrudan görüntüleme yöntemlerinin dışmerkezliliği yüksek gezegenleri bulmak konusundaki başarısı öne çıkmaktdır. Geçiş yönteminde de pek çok yüksek dışmerkezlilikli gezegen bulunduğu halde ortanca 0'a yakındır.

Keman Diyagramları

Keman diyagramları da kategorik verinin içerisindeki istatistiksel dağılımları görselleştirmek için başvurulan bir yöntemdir.

Örnek: Kütle Dağılımları

Farklı keşif yöntemleri farklı kütle aralıklarındaki gezegenleri keşfetmeye daha duyarlıdır. Örneğin Doğrudan Görüntüleme uzak ve büyük gezegenleri keşfederken; zamanlama, kütleçekimsel mercek ve geçiş yöntemi daha küçük kütleli gezegenleri keşfetmeye daha duyarlıdır. Dikine hız yönteminde ise gezegen kütlesi yerine ($m_g$) onun yörünge eğim açısının sinüsüyle çarpımı elde edilebilir ($m_g~sin~i$). Bu nedenle dikine hız yöntemi göz ardı edilerek yine sadece istatistiksel olarak anlamlı sayıda gezegenin keşfedildiği ve kütlelerinin de bilindiği yöntemlere konsantre olunacaktır.

In [33]:
# Daha once bu veri islendigi icin tekrar orjinal halini elde etmek gerekebilir
# Istatistiksel olarak anlamli sayida ornek barindiran 4 kesif yontemi
exoeu_mass = exoeu.dropna(subset=['mass'])
massdist = [exoeu_mass[exoeu_mass['detection_type'] == "Primary Transit"]['mass'],
            exoeu_mass[(exoeu_mass['detection_type'] == "Imaging")]['mass'],
           exoeu_mass[exoeu_mass['detection_type'] == "Microlensing"]['mass'],
           exoeu_mass[exoeu_mass['detection_type'] == "Timing"]['mass']]

Basit bir keman grafiği doğrudan görüntüleme (ing. imaging) yönteminin daha büyük gezegenleri bulmaya daha yanlı olduğu ve dağılımının $12 M_{jup}$ civarında ortalaması olan bir normal dağılıma benzediğini göstermektedir.

In [34]:
etiketler=["Transits","Rad.Vel.","Imaging","Lensing"]
plt.violinplot(massdist)
plt.xticks([1,2,3,4], etiketler, rotation='vertical')
plt.show()

Saçılma Grafikleri

Özellikle parametreler arası ilişkileri (korelasyonları) araştırmak ve görselleştirmek için kullanılmasının yanı sıra astronomide zaman serisi verinin (ışık, dikine hız eğrileri vs.) yanı sıra başka tanım kümelerindeki verileri (tayflar, tayfsal enerji dağılımları vs.) grafik etmek için sıklıkla başvurulur.

Örnek: Karasal Gezegenler İçin Kütle Yarıçap Diyagramı

Ötegezegenlerin tüm çeşitliliğine karşın fizik kurallar gereği karasal gezegenler için bir kütle-yarıçap ilişkisi beklenir. Dev gaz gezegenleri çok sayıda bulunan yıldızına yakın sıcak-Jüpiterler domine ettiği ve yakınlık etkileri nedeniyle bu cisimlerin büyük bir kısmının genişlemiş atmosferlere sahip olduğu için bu ilişki ancak uzun dönemli yeterli sayıda gaz gezegen keşfedildiği vakit çalışılabilecek bir konu olarak durmaktadır ve bu parametre uzayında çeşitlilik de daha fazladır.

Bu ilişkiyi görselleştirmek üzere yine öncelikle verinin ona göre düzenlenmesi gerekecektir. Hassas yarıçap ölçümleri ancak geçiş yöntemiyle yapılabileceği için örneklemi öncelikle geçiş yapan gezegenlerle sınırlamak; bunlar arasından da dikine hızla doğası kesinleştirilen, dolayısıyla kütlesi bilinenleri almak gerekecektir. Daha detaylı bir çalışma için yalnızca bu değerler üzerindeki belirsizliği büyük olmayan (örn. <%5), güvenilir kaynaklardan gelen veriler seçilebilir. Ancak örnek olarak exoplanet.eu veritabanında yarıçap ve kütlesi bulunan tüm gezegenler kullanılacaktır.

In [35]:
print(plt.style.available)
['Solarize_Light2', '_classic_test_patch', 'bmh', 'classic', 'dark_background', 'fast', 'fivethirtyeight', 'ggplot', 'grayscale', 'seaborn', 'seaborn-bright', 'seaborn-colorblind', 'seaborn-dark', 'seaborn-dark-palette', 'seaborn-darkgrid', 'seaborn-deep', 'seaborn-muted', 'seaborn-notebook', 'seaborn-paper', 'seaborn-pastel', 'seaborn-poster', 'seaborn-talk', 'seaborn-ticks', 'seaborn-white', 'seaborn-whitegrid', 'tableau-colorblind10']
In [36]:
from astropy import constants as const
mpl.style.use("seaborn-dark")
plt.figure(figsize=(9,4))
Rjup_earth = const.R_jup / const.R_earth
Mjup_earth = const.M_jup / const.M_earth
tr_karasal = exoeu[(exoeu['detection_type'] == 'Primary Transit') & 
                   (exoeu['radius']*Rjup_earth< 1.8) &
                  (exoeu['mass']*Mjup_earth< 5.0)]
trkarasal_massrad = tr_karasal.dropna(subset=['mass','radius'])
trkarasal_massrad.plot(x="mass",y="radius",kind="scatter")
plt.xlabel("Kutle ($M_{\oplus}$)")
plt.ylabel("Yaricap ($R_{\oplus}$)")
plt.show()
<Figure size 648x288 with 0 Axes>

İlk bakışta bir ilişki yokmuş gibi görünüyor ancak grafiğin eksenleri logaritmik ölçekte çizdirilirse daha iyi bir fikir edinmek mümkün olabilir.

In [37]:
plt.figure(figsize=(9,4))
trkarasal_massrad.plot(x="mass",y="radius",kind="scatter")
plt.xscale("log")
plt.yscale("log")
plt.grid(which="minor")
plt.xlabel("Kutle ($M_{\oplus}$)")
plt.ylabel("Yaricap ($R_{\oplus}$)")
plt.show()
<Figure size 648x288 with 0 Axes>

Her ne kadar özellikle küçük kütleliler tarafında doğrusalilişki görünse dek kütle büyüdükçe ilişkiden ayrılan beklenenden küçük yarıçaplı gezegen sayısı artmaktadır. Bu da bu gezegenlerin atmosferlerinden uçucuların ayrılmış olacağı şeklinde yorumlanabilir. Ancak böyle bir açıklamanın mutlaka fiziksel yaklaşımlarla desteklenmesi gerekir.

seaborn paketi saçılma grafiklerinin görselleştirilmesinde regplot aracılığıyla sadece bir saçılma grafiği değil aynı zamanda bir de model opsiyonu sağlar. Aynı ilişki seaborn.replot fonksiyonu ile görselleştirildiğinde aşağıdaki grafik elde edilebilir.

In [38]:
import seaborn as sns
sns.regplot(x='mass', y='radius', data=trkarasal_massrad)
plt.show()

Balon Diyagramları

Balon diyagramları (bubble diagrams) saçılma (scatter) grafiklerinin özel bir türüdür. Veri noktasını çizdirmek üzere kullanılacak çember (balon) büyüklüğünün bir değişken üzerinden belirlenmesiyle grafik üç boyutlu hale gelmiş olur. pyplot.plot() ya da pyplot.scatter() fonksiyonlarının sırasıyla ms (marker size) ve s (size) parametrelerine bu üçüncü boyutu belirleyecek dizi değişken geçirilerek grafiğin üçüncü boyutu belirlenir.

Örnek: Sıcak Jüpiterler Metalce Zengin Yıldızları Sever

Yıldızına yakın (yörünge dönemi küçük), dolayısıyla sıcak, dev gaz gezegenlerin (sıcak-Jüpiterler) diğer gezegenlere göre metalce zengin yıldızlar etrafında daha sık bulunduğuna ilişkin bulgulara rastlanmıştır (Osborn & Bayliss 2019). Geçiş yöntemiyle keşfedilen gezegenlerin yarıçapları hassas olarak belirlenebildiğinden kütle yerine 3. boyut olarak yarıçap kulllanılmak suretiyle grafik sadece kısa yörünge dönemli gezegenler için çizdirildiğinde bu durum açıkça görülebilir.

In [39]:
%matplotlib notebook
%matplotlib notebook
from matplotlib import pyplot as plt
mpl.style.use("default")
hotpl = exoeu[(exoeu["orbital_period"] < 5) & (exoeu["mass"] < 13.)]
# Yaricapa gore sembol buyuklugu olceklendirmesi icin
# keyfi secilmis 100 carpani kullanilmistir
radii = hotpl["radius"]*100
hotpl.plot(x="orbital_period",y="star_metallicity",s=radii,kind="scatter")
plt.axhline(y=0.0,ls="--",c="red")
plt.axvline(x=0.7,ls="--",c="orange")
plt.xlabel("Yorunge Donemi (gun)")
plt.ylabel("[Fe / H] (dex)")
plt.show()

En kısa yörünge dönemli gezegenler ($P < 0.7$ gün, turuncu dik doğrunun sol tarafı) dışarıda bırakılacak olursa Güneş bolluğundan metalce daha fakir ($[Fe / H] > 0.0$, kırmızı yatay doğrunun altı) barınak yıldızlar etrafında da büyük gezegenler varsa da daha küçük gezegenlerin buradaki ağırlığı daha fazladır. Metalce zengin yıldızlar etrafında (kırmızı yatay doğrunun üstü) hem daha fazla sayıda gezegen olması, hem de bunların büyük bölümünün dev gaz gezegenler olması, geçiş yöntemiyle daha kolay keşfedilen sıcak-Jüpiter türü gezegenlerin metalce zengin yıldızları tercih ettiğini göstermektedir.

Grafiğe bir dördüncü boyut olarak barınak yıldız sıcaklığı da sembollerin gösteriminde bir renk skalası kullanılarak eklenebilir. Bu durumda sıcak gaz devlerinin metalce zengin yıldızların yanı sıra aynı zamanda sıcak yıldızları da tercih edip etmediği de denetlenmiş olur. Bunun için renk haritası (color map) parametresi cmap amaca uygun olarak seçilen bir desene atanır. Gezegen barınağı yıldızlar genelde soğuk yıldızlar olduğu için YlOrRd yıldız renkleriyle uyumlu olması bakımından da iyi bir seçim olacaktır. Ancak, bu desende sıcaklık arttıkça renk daha kırmızı olacağı için desenin ters çevrilmesi gerekecektir. matplotlib renk haritalarının hepsi için terslerine karşılık gelen birer harita daha bulunmaktadır. Bu desenlere erişmek için desen isminin sonuna _r eklenmesi yeterli olacaktır. Örnekte bu YlOrRd_r 'ye karşılık gelmektedir.

In [40]:
%matplotlib inline
from matplotlib import pyplot as plt
plt.figure(figsize=(12,8))
# Grafigin buyuklugune gore olceklendirme carpanini
# degistirmek gerekebilir
radii = hotpl["radius"]*200
plt.scatter(x=hotpl["orbital_period"],y=hotpl["star_metallicity"],s=radii, 
           c=hotpl["star_teff"], cmap="YlOrRd_r")
plt.axhline(y=0.0,ls="--",c="darkblue")
plt.axvline(x=0.7,ls="--",c="royalblue")
plt.xlabel("Yorunge Donemi (gun)")
plt.ylabel("[Fe / H] (dex)")
plt.colorbar(label="T$_{eff}$")
plt.show()

Bu grafiğe bakarak böyle bir çıkarımda bulanmak kolay görünmemektedir. Grafiğin dayalı olduğu veri setinde tüm gezegenlerin değil; belirlenen koşulları (geçiş yapan P < 5 gün yörünge dönemli gezegenler) sağlayan yörünge dönemi, yarıçapı, barınak yıldız metalisitesi ve etkin sıcaklığı veritabanında bulunan gezegenlerin bulunduğu unutulmamalıdır.

Zamana Bağlı Değişimlerin Görselleştirilmesi

Dikine hız, ışık eğrileri ya da gözlemsel tayflar gibi gibi astronomların sıklıkla başvurduğu zamana ya da dalgaboyuna bağlı değişimleri gösteren verilerin görselleştirlmesi için de saçılma grafikleri kullaınılabliir. Ancak genellikle gözlemsel hataların da grafik üzerine aktarılmasının beklendiği bu türden veri görselleştirmelerinde matplotlib.errorbar() fonksiyonu gibi buna olanak sağlayan fonksiyonlar daha sık tercih edilmektedirler.

Örnek: Bir Geçiş Işık Eğrisi ve Modelinin Grafiği

HAT-P-23b ötegezegenin Exoplanet Transit Database açık veritabanından alınmış 123 numaralı geçiş ışık eğrisi ve bu ışık eğrisine sistemin temel parametreleri dikkate alınarak EXOFAST (Eastman vd. 2013, 2017) yapılmış bir geçiş ışık eğrisi modeli veri klasörü altında sunulmuştur. Bu ışık eğrisi ve modeli matplotlib.errorbar fonksiyonu kullanılarak aşağıdaki şekilde çizdirilmiştir. Gözlemsel hatalar sadece normalize göreli akıların üzerinde olduğundan hata değerleri dizisinin yerr parametresinden sağlanması yeterli olacaktır.

In [41]:
%matplotlib inline
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
mpl.style.use("Solarize_Light2")
isik_egrisi = pd.read_csv("veri/hatp23_etd123_converted_datasubset.dat", delimiter="\t", 
                         index_col="#", skipinitialspace=True)
model = pd.read_csv("veri/hatp23_etd123_converted_model.dat", delimiter="\t",
                   skipinitialspace=True)
In [42]:
isik_egrisi.head()
Out[42]:
Label BJD-TDB mag_dn mag_err_dn
#
1 Row_1 2.458376e+06 1.004781 0.005284
2 Row_2 2.458376e+06 1.007404 0.005298
3 Row_3 2.458376e+06 0.993975 0.005227
4 Row_4 2.458376e+06 1.006068 0.005291
5 Row_5 2.458376e+06 1.008043 0.005301
In [43]:
model.head()
Out[43]:
#BJD-TDB flux
0 2.458376e+06 0.999847
1 2.458376e+06 0.999847
2 2.458376e+06 0.999847
3 2.458376e+06 0.999847
4 2.458376e+06 0.999847

Gerek ışık eğrisi, gerek modelinde zaman Güneş-Yer ikilisinin kütle merkezine indirgenmiş Julien günü birimindedir (Dynamical Barycentric Julian Date, BJD-TDB). Her ne kadar ışık eğrisinde mag_dn ve mag_err_dn sütunlarında verilen değerlerin kadir (ing. magntiude) biriminde parlaklıklar olduğu düşünülebilirse de değerlerden ve modelin değerlerinden bu sütunların aslında göreli normalize akı ve hatası olduğu anlaşılmaktadır. Bir karışıklık olmaması açısından bu sütunların isimlerini değiştirmekte fayda vardır.

In [44]:
isik_egrisi.rename(columns = {'mag_dn':'normflux', 'mag_err_dn':'normflux_err'}, inplace = True)
In [45]:
isik_egrisi.head()
Out[45]:
Label BJD-TDB normflux normflux_err
#
1 Row_1 2.458376e+06 1.004781 0.005284
2 Row_2 2.458376e+06 1.007404 0.005298
3 Row_3 2.458376e+06 0.993975 0.005227
4 Row_4 2.458376e+06 1.006068 0.005291
5 Row_5 2.458376e+06 1.008043 0.005301
In [46]:
plt.errorbar(isik_egrisi['BJD-TDB'], isik_egrisi['normflux'], yerr=isik_egrisi['normflux_err'],
            fmt=".", color="blue")
# veri zaman sirasinda degilse grafik beklendigi gibi cizdirilmeyebilir.
model.sort_values(by="#BJD-TDB", inplace=True)
plt.plot(model["#BJD-TDB"], model["flux"], "r-", lw=2)
plt.xlabel("Zaman (BJD-TDB)")
plt.ylabel("Goreli Aki")
plt.show()

Örnek: Tayfsal Verinin Grafiği

Tayfsal verilerde genellikle gözlemsel verinin hatası bulunmaz. Buna karşılık tayfsal çizgi profilin daha iyi takip edebilmek üzere veri noktalarının doğrularla birleştirilmesi tercih edilir. Bu nedenle saçılma grafikleri yerine eğri grafikleri (line plots) tercih edilebilir. Özellikle çizgi profillerine zoom yaparak daha dar dalgaboyu aralıklarında tayfı inceleyebilmek için bu grafiği %matplotlib notebook arkayüzü (backend) ile çizdirmekte fayda olacaktır.

In [47]:
%matplotlib notebook
%matplotlib notebook
import matplotlib.pyplot as plt
import pandas as pd
tayf = pd.read_csv("veri/spectrum_normalized.dat", delimiter="  ", 
                        skipinitialspace=True, engine='python')
tayf.plot(kind="line", x="Wavelength", y="Flux")
plt.ylim((0.0,1.1))
plt.xlabel("Dalgaboyu ($\AA$)")
plt.ylabel("Goreli aki")
plt.show()

Kaynaklar