Visualisasi Dinamis dan Interaktif menggunakan Altair

Python memiliki banyak perpustakaan visualisasi untuk menempatkan data Anda ke dalam perspektif visual, belum lagi interaktivitas. Kami memiliki Matplotlib yang merupakan perpustakaan yang sangat matang & populer dengan banyak opsi penyesuaian. Perpustakaan lain seperti seaborn yang menawarkan pembungkus tingkat tinggi di atas matplotlib untuk menghasilkan visual yang lebih baik dengan kode yang tidak terlalu rumit. Demikian pula, untuk plot dinamis dan interaktif, kami memiliki plotly, bokeh, dan folium.

Di antara semua ini, kami juga memiliki perpustakaan Altair indah yang bersifat deklaratif dan tata bahasanya didasarkan pada Vega & Vega-lite. Salah satu fitur utama Altair adalah sintaksisnya yang sederhana dan intuitif, yang memungkinkan pengguna dengan cepat membuat visualisasi kompleks dengan kode minimal.

Salah satu fitur paling canggih dari Altair adalah kemampuannya untuk dengan mudah menggabungkan berbagai jenis bagan dalam satu visualisasi. Hal ini memungkinkan pengguna untuk membuat grafik kompleks yang secara efektif mengkomunikasikan banyak lapisan data.

Keuntungan utama lain dari Altair adalah interaktivitasnya. Hanya dengan beberapa baris kode, pengguna dapat membuat visualisasi dinamis yang memungkinkan mereka menjelajahi data dengan cara baru.

Berikut tampilan Sintaks Altair:

import altair as alt
from vega_datasets import data

iris = data.iris.url

chart1 = alt.Chart(iris).mark_point().encode(
    x='petalLength:Q',
    y='petalWidth:Q',
    color='species:N'
).properties(
    height=300,
    width=300
)

chart2 = alt.Chart(iris).mark_bar().encode(
    x='count()',
    y=alt.Y('petalWidth:Q', bin=alt.Bin(maxbins=30)),
    color='species:N'
).properties(
    height=300,
    width=100
)

chart1 | chart2

Kode di atas mungkin tampak rumit dan sulit dipahami, yakinlah, kami akan memecahkan kodenya di akhir artikel ini.

Mari selami… dan seiring berjalannya waktu, kita akan dapat menghargai tata bahasa Vega yang indah. Ini mungkin artikel pengantar, namun memiliki kekuatan untuk membawa Anda mulai mempertimbangkan Altair sebagai pengemudi harian.

Memasang & Mengimpor

  1. panda untuk perselisihan data
  2. vega_datasetsuntuk data
  3. altair untuk … yah…
#Installation
pip install pandas
pip install vega_datasets
pip intsall altair

#Imports
import pandas as pd
from vega_datasets import data
import altair as alt

Memuat Kumpulan Data

Kami akan menggunakan kumpulan data 'mobil' favorit saya. Berikut cara menyebutnya.

cars = data.cars()

Kumpulan data tersebut berisi informasi tentang berbagai model mobil dan efisiensi bahan bakarnya (diukur dalam mil per galon, atau mpg). Ia juga memiliki informasi seputar asal mobil, perpindahan, jumlah silinder, tenaga kuda, berat, model tahun dan akselerasi. Dan yang jelas nama mobilnya.

Merencanakan

  1. Merencanakan grafik Altair mengharuskan kita mendeklarasikan data di Bagan tingkat dasar terlebih dahulu. Datanya bisa dalam bentuk kerangka data Pandas, objek data alt, url yang menunjuk ke file json dan csv, atau data geografis.
  2. Kita juga perlu mendefinisikan tanda, yaitu informasi tentang bagaimana kita ingin atribut visual kita ditampilkan pada plot. Bisa berupa titik, garis, batang, dll.
  3. Pengkodean kemudian digunakan untuk memetakan kolom ke atribut visual plot.

Mari kita gabungkan semua ini.

Pertama-tama kita memanggil metode Chart dan mengarahkannya ke kerangka data mobil kita. Sekarang kita beritahu Altair bentuk tanda apa yang kita inginkan. Di sini, kita memanggil metode mark_pointkarena kita menginginkan poin untuk plot ini.

alt.Chart(cars).mark_point()

Karena kita belum memberikan koordinatnya kepada Altair, semua titik ditempatkan di satu tempat. Jadi kita mempunyai 406 poin yang tumpang tindih pada satu titik di Bagan.

Yang tersisa hanyalah memberi tahu Altair di mana kita menginginkan titik-titik ini. Di sini, kita akan memplot 'mil per galon' pada sumbu x sebagai titik.

alt.Chart(cars).mark_point().encode(
    x='Miles_per_Gallon'
)

Kami mendapatkan plot 1D dari semua titik data yang menggambarkan 'mpg' untuk setiap mobil.

Mari kita tambahkan ‘bobot’ke sumbu y.

alt.Chart(cars).mark_point().encode(
    x='Miles_per_Gallon',
    y='Weight_in_lbs'
)

Kami mendapatkan plot sebar yang ditata dengan baik karena titik kami sekarang dikodekan dengan nilai pada setiap sumbu.

Bagaimana kalau kita mengubah variabel sumbu y menjadi variabel kategori. Mari kita gunakan negara ‘asal’.

alt.Chart(cars).mark_point().encode(
    x='Miles_per_Gallon',
    y='Origin'
)

Kita bisa melihat bagaimana data ‘mpg’tersebar di ketiga negara tersebut.

Bagaimana kalau menggunakan jenis tanda yang berbeda. Mari beralih ke tick menggunakan metode mark_tick.

alt.Chart(cars).mark_point().encode(
    x='Miles_per_Gallon',
    y='Origin'
)

Kita dapat menambahkan dimensi lain dengan mendefinisikan parameter warna. Mari kita gunakan variabel 'Silinder'. Mari kita ambil mobil dengan 4, 6 dan 8 silinder saja.

#Filtering to get cars with 4, 6 and 8 cylinders
cars = cars.loc[cars.Cylinders.isin([4,6,8])]
alt.Chart(cars).mark_tick().encode(
    x='Miles_per_Gallon',
    y='Origin',
    color='Cylinders'
)

Mari beralih kembali ke plot sebar antara 'mpg' & 'weight' dan membagi sumbu x menjadi beberapa bin. Tata bahasa Altair menonjol di sini karena kita cukup menetapkan objek alt.X ke sumbu x. Sekarang kita bisa memasukkan parameter lain ke dalamnya. Mari aktifkan binning dengan meneruskan nilai boolean ke parameter bin. Kami akan menyimpan kumpulan data yang difilter ke mobil 4, 6, dan 8 silinder.

alt.Chart(cars).mark_point().encode(
    x=alt.X('Miles_per_Gallon', bin=True),
    y='Weight_in_lbs',
    color='Cylinders'
)

Kita dapat melihat bahwa binning kini telah mengelompokkan titik-titik menjadi garis vertikal. Mari kita ganti tandanya dengan jeruji.

alt.Chart(cars).mark_bar().encode(
    x=alt.X('Miles_per_Gallon', bin=True),
    y='Weight_in_lbs',
    color='Cylinders'
)

Kami mendapatkan plot batang bertumpuk yang dengan jelas menggambarkan bahwa kendaraan yang lebih berat memiliki efisiensi bahan bakar yang lebih rendah. Selain itu, mobil dengan jumlah silinder lebih banyak memiliki efisiensi lebih rendah seperti yang diharapkan.

Bagaimana kalau mengganti sumbu y dengan jumlah nilai di setiap nampan pada sumbu X. Kita dapat melakukannya dengan mengganti nama kolom yang diberikan pada sumbu Y dengan fungsi count(). Mari kita hilangkan parameter warna untuk saat ini.

alt.Chart(cars).mark_bar().encode(
    x=alt.X('Miles_per_Gallon', bin=True),
    y='count()'
)

Kami sekarang memiliki histogram bagus yang menghitung nilai di setiap nampan yang ditentukan pada sumbu X. Kita dapat mengubah orientasi hanya dengan menugaskan ulang sumbunya.

alt.Chart(cars).mark_bar().encode(
    x='count()',
    y=alt.Y('Miles_per_Gallon', bin=True)
)

Anda dapat mengubah jumlah bin dengan meneruskan objek alt.Bin ke parameter bin alih-alih boolean. Hal ini memungkinkan lebih banyak argumen yang bisa masuk.

Mari kita tambah jumlah bin di sini dengan menggunakan parameter maxbins di dalam objek alt.Bin. Hati-hati dengan informasinya — keseimbangan kebisingan saat Anda menggunakan parameter seperti itu.

alt.Chart(cars).mark_bar().encode(
    x=alt.X('Miles_per_Gallon', bin=alt.Bin(maxbins=25)),
    y='count()'
)

Bagaimana kalau kita mengembalikan parameter warna.

alt.Chart(cars).mark_bar().encode(
    x=alt.X('Miles_per_Gallon', bin=alt.Bin(maxbins=10)),
    y='count()',
    color='Origin'
)

Kami sekarang memiliki histogram bertumpuk.

Mari kita perkenalkan dimensi lain di sini dengan mendefinisikan parameter kolom. Saya akan menggunakan variabel 'Silinder' untuk ini. Ini akan membagi plot menjadi beberapa plot yang ditumpuk dalam kolom, masing-masing menggambarkan sebuah kategori dalam variabel Silinder. Gunakan parameter row jika Anda ingin plot disusun dalam baris.

alt.Chart(cars).mark_bar().encode(
    x=alt.X('Miles_per_Gallon', bin=alt.Bin(maxbins=10)),
    y='count()',
    color='Origin',
    column='Cylinders'
)

Bagaimana jika kita menetapkan parameter warna ke variabel kontinu.

alt.Chart(cars).mark_bar().encode(
    x=alt.X('Miles_per_Gallon', bin=alt.Bin(maxbins=10)),
    y='count()',
    color='Horsepower',
    column='Cylinders'
)

Perhatikan palet warna berubah menjadi kontinu dan legenda digantikan oleh bilah warna untuk menggambarkan hal yang sama.

Di sini saya telah menggunakan variabel Silinder sebagai variabel kategorikal. Kita bisa meminta Altair mengubah cara pembacaan variabel tersebut dengan memasukkan :Qsetelahnama kolom. Hal ini menghindari kebutuhan untuk mengubah tipe data kolom dalam kumpulan data kami.

Mari kita beralih ke satu plot dan menggunakan Silindersebagai warna. Kali ini kita akan menggunakannya sebagai variabel kontinu.

alt.Chart(cars).mark_bar().encode(
    x=alt.X('Miles_per_Gallon', bin=alt.Bin(maxbins=10)),
    y='count()',
    color='Cylinders:Q'
)

Dan jika kita ingin beralih kembali ke Silinder menjadi variabel kategori. Menggunakan :Nakan membantu Altair membaca Silindersebagai variabel nominal.

alt.Chart(cars).mark_bar().encode(
    x=alt.X('Miles_per_Gallon', bin=alt.Bin(maxbins=10)),
    y='count()',
    color='Cylinders:N'
)

Seringkali ada kebutuhan untuk mengumpulkan data dan kita dapat melakukannya di sini tanpa harus mengelompokkannya terlebih dahulu berdasarkan kerangka data kita dan kemudian memasukkannya sebagai masukan ke altair. Kami menggunakan fungsi mean di sini untuk melakukannya.

Mari kita lihat efisiensi bahan bakar rata-rata (‘mpg’)mobil di setiap negara asal. Mari kita tetap berpegang pada bar untuk saat ini. Karena kita ingin membandingkan rata-rata mpgsetiap negara, kita dapat menetapkan warna tersendiri pada setiap batang dengan memetakan 'Origin' ke parameter warna.

alt.Chart(cars).mark_bar().encode(
    x='mean(Miles_per_Gallon):Q',
    y='Origin:N',
    color='Origin:N'
)

Mari kita menetapkan warna ke suatu agregat. Mari kita berhitung.

alt.Chart(cars).mark_bar().encode(
    x='mean(Miles_per_Gallon):Q',
    y='Origin:N',
    color='count()'
)

Kita dapat memecah sumbu X menjadi beberapa bin, bukan mean, dan memberi setiap bagian warna sesuai hitungan.

alt.Chart(cars).mark_bar().encode(
    x=alt.X('Miles_per_Gallon:Q', bin=alt.Bin(maxbins=10)),
    y='Origin:N',
    color='count()'
)

Bagaimana kalau kita beralih ke diagram lingkaran. Kami sekarang memplot jumlah mobil dalam kumpulan data berdasarkan asal. Kita mengganti jenis tanda menjadi busur, menetapkan sudut setiap irisan di parameter theta dan kemudian menentukan cara kerja warna. Ingat, kita memiliki objek alt yang relevan yang dapat kita teruskan ke parameter ini dan objek ini dapat mengambil argumen tambahan untuk menyesuaikan keluaran kita.

Perhatikan bahwa kita sekarang telah beralih ke cara yang lebih eksplisit dalam mengemukakan argumen. Ini terutama bersifat preferensial.

alt.Chart(cars).mark_arc().encode(
    theta=alt.Theta(
        field='Miles_per_Gallon', 
        type='quantitative', 
        aggregate='count'
        ),
    color=alt.Color(
        field='Origin', 
        type='nominal'
        )
)

Kita dapat menentukan parameter lebih lanjut pada metode mark_arc dan mengubahnya menjadi plot donat. Mari kita sampaikan argumen innerRadius & radius.

alt.Chart(cars).mark_arc(
    innerRadius=65,
    radius=120
    ).encode(
        theta=alt.Theta(
            field='Miles_per_Gallon', 
            type='quantitative', 
            aggregate='count'
            ),
        color=alt.Color(
            field='Origin', 
            type='nominal'
            )
)

Bagaimana kalau kita menetapkan variabel ke radius. Hal ini dapat dilakukan dengan menggunakan objek alt.Radius.

alt.Chart(cars).mark_arc(
    innerRadius=30
    ).encode(
        theta=alt.Theta(
            field='Miles_per_Gallon', 
            type='quantitative', 
            aggregate='count',
            stack=True
            ),
        color=alt.Color(
            field='Cylinders', 
            type='ordinal'
            ),        
        radius=alt.Radius(
            field='Miles_per_Gallon:Q',
            aggregate='count'
            )
)

Bagan ini akan lebih masuk akal jika kategorinya lebih banyak (katakanlah 5) dan memiliki data yang sebanding dalam hal jumlah.

Mari kita visualisasikan plot gelembung yang menunjukkan hubungan antara mpg dan berat kendaraan. Kita dapat menambahkan dimensi lain dengan mengalokasikan ukuran ke perpindahandan warna keasing.

alt.Chart(cars).mark_point(
    fillOpacity=0.2
    ).encode(
        x='Miles_per_Gallon',
        y='Weight_in_lbs',
        size='Displacement',
        color='Origin'
)

Altar memberi Anda opsi untuk menggabungkan beberapa jenis bagan. Untuk menggabungkan beberapa plot, Anda mempunyai opsi untuk menggunakan operator seperti‘+’, ‘&’ dan ‘|’. Anda juga mempunyai opsi untuk menggunakan vconcat dan hconcat. Contoh untuk diikuti.

Bagaimana dengan memeriksa perubahan efisiensi bahan bakar (mpg) secara keseluruhan dari waktu ke waktu di negara-negara ini dan selagi kita melakukannya, mari kita plot interval kepercayaannya. Untuk ini kami menggabungkan mark_line dan mark_errorband.

line = alt.Chart(cars).mark_line().encode(
    x=alt.X(
        field='Year', 
        type='temporal'
        ),
    y=alt.Y(
        field='Miles_per_Gallon', 
        type='quantitative', 
        aggregate='mean'
        )
)

band = alt.Chart(cars).mark_errorband(
    extent='ci'
    ).encode(
        x=alt.X(
            field='Year', 
            type='temporal'
            ),
        y=alt.Y(
            field='Miles_per_Gallon', 
            type='quantitative', 
            title='Miles Per Gallon'
            )
)

line + band

Mari tandai garis vertikal pada plot untuk memisahkan mobil yang dibuat sebelum tahun 75 dan sesudahnya.

line = alt.Chart(cars).mark_line().encode(
    x=alt.X(
        field='Year', 
        type='temporal'
        ),
    y=alt.Y(
        field='Miles_per_Gallon', 
        type='quantitative', 
        aggregate='mean'
        )
)

band = alt.Chart(cars).mark_errorband(
    extent='ci'
    ).encode(
        x=alt.X(
            field='Year', 
            type='temporal'
            ),
        y=alt.Y(
            field='Miles_per_Gallon', 
            type='quantitative', 
            title='Miles Per Gallon'
            )
)

xrule = alt.Chart(cars).mark_rule(
    color='gray', 
    strokeWidth=1.5,
    strokeDash=[10,5]
    ).encode(
        x=alt.datum(
            alt.DateTime(
                year=1975, 
                month='December', 
                date=31
                )
            )
)

line + band + xrule

Anda dapat melihat plot interaktif yang dapat Anda arahkan mouse untuk informasi lebih lanjut.

Berbicara tentang interaktivitas. Mari kita lihat cara kerjanya.

Saya akan beralih kembali ke plot pencar antara mpg & berat. Warna menunjukkan asal kendaraan tersebut. Posting codingnya, saya menggunakan metode interaktif. Ini akan memberi kita tingkat interaktivitas dasar dengan garis plot pan & zoom.

alt.Chart(cars).mark_point().encode(
    x='Weight_in_lbs:Q',
    y='Miles_per_Gallon:Q',
    color='Origin:N'
).interactive()

Mari buat beberapa plot dan coba ciptakan interaktivitas di antara plot-plot tersebut.

Mari gunakan plot di atas apa adanya dan tambahkan plot lain di bawahnya menggunakan metode vconcat. Plot kedua dapat menampilkan jumlah kendaraan di negara asal tertentu.

Apa yang ingin kami bangun adalah serangkaian plot yang dapat berinteraksi satu sama lain. Misalnya. memilih titik pada plot sebar secara otomatis mengubah data yang ditampilkan di plot terkait lainnya.

Karena pan & zoom bukan satu-satunya elemen interaktif yang ingin kita miliki, mari kita hilangkan metode interaktif.

scatter_plot = alt.Chart(cars).mark_point().encode(
    x='Weight_in_lbs:Q',
    y='Miles_per_Gallon:Q',
    color='Origin:N'
)

bar_plot = alt.Chart(cars).mark_bar().encode(
    x='count()',
    y='Origin:N',
    color='Origin:N'
)

alt.vconcat(scatter_plot, bar_plot)

Sekarang kita sudah mempunyai plotnya, langkah 1 adalah mengaktifkan pemilihan titik di plot sebar. Kami menggunakan objek alt.selection_intervaluntuk mengontrol hal yang sama. Kemudian kita memasukkan objek seleksi ke properti plot sebar sehingga merespons seleksi.

select = alt.selection_interval(encodings=['x', 'y'])

scatter_plot = alt.Chart(cars).mark_point().encode(
    x='Weight_in_lbs:Q',
    y='Miles_per_Gallon:Q',
    color='Origin:N'
).properties(
    selection=select
)

bar_plot = alt.Chart(cars).mark_bar().encode(
    x='count()',
    y='Origin:N',
    color='Origin:N'
)

alt.vconcat(scatter_plot, bar_plot)

Saat ini seleksi tidak melakukan apa-apa tapi kami tahu seleksi itu ada. Mari kita petakan sedemikian rupa sehingga titik-titik di dalam pilihan disorot sementara titik lainnya berubah warna, katakanlah abu-abu. Untuk melakukannya, kita menggunakan objek alt.condition ke parameter color dan menggunakan pilihan yang ditentukan sebelumnya sebagai kondisi.

select = alt.selection_interval(encodings=['x', 'y'])

scatter_plot = alt.Chart(cars).mark_point().encode(
    x='Weight_in_lbs:Q',
    y='Miles_per_Gallon:Q',
    color=alt.condition(select, 'Origin:N', alt.value('Lightgray'))
).properties(
    selection=select
)

bar_plot = alt.Chart(cars).mark_bar().encode(
    x='count()',
    y='Origin:N',
    color='Origin:N'
)

alt.vconcat(scatter_plot, bar_plot)

Sekarang seleksi sudah sesuai dengan yang kita inginkan, mari kita hubungkan ke diagram batang sehingga diagram batang menampilkan distribusi frekuensi dari tanda yang dipilih. Kita menggunakan metode transform_selectpada diagram batang untuk melakukannya.

select = alt.selection_interval(encodings=['x', 'y'])

scatter_plot = alt.Chart(cars).mark_point().encode(
    x='Weight_in_lbs:Q',
    y='Miles_per_Gallon:Q',
    color=alt.condition(select, 'Origin:N', alt.value('Lightgray'))
).properties(
    selection=select
)

bar_plot = alt.Chart(cars).mark_bar().encode(
    x='count()',
    y='Origin:N',
    color='Origin:N'
).transform_filter(select)

alt.vconcat(scatter_plot, bar_plot)

Plot interaktif yang luar biasa dengan basis kode yang sangat intuitif. Bagaimana dengan beberapa pilihan terbalik di mana kita dapat memilih bilah pada diagram batang dan hanya menampilkan titik-titik negara terkait di diagram sebar.

select = alt.selection_interval(encodings=['x', 'y'])
multiple_select = alt.selection_multi(fields=['Origin'])

scatter_plot = alt.Chart(cars).mark_point().encode(
    x='Weight_in_lbs:Q',
    y='Miles_per_Gallon:Q',
    color=alt.condition(select, 'Origin:N', alt.value('Lightgray'))
).properties(
    selection=select
).transform_filter(multiple_select)

bar_plot = alt.Chart(cars).mark_bar().encode(
    x='count()',
    y='Origin:N',
    color='Origin:N'
).transform_filter(select).properties(selection=multiple_select)

alt.vconcat(scatter_plot, bar_plot)

Salah satu contoh terakhir dari fungsi luar biasa ini.

select = alt.selection_interval(encodings=['x', 'y'])
multiple_select = alt.selection_multi(fields=['Origin'])

scatter_plot = alt.Chart(cars).mark_point().encode(
    x='Weight_in_lbs:Q',
    y='Miles_per_Gallon:Q',
    color=alt.condition(select, 'Origin:N', alt.value('Lightgray'))
).properties(
    selection=select
).transform_filter(multiple_select)

bar_plot = alt.Chart(cars).mark_bar().encode(
    x='mean(Weight_in_lbs)',
    y=alt.Y('Miles_per_Gallon', bin=alt.Bin(maxbins=10)),
    color='Origin:N'
).transform_filter(select).properties(selection=multiple_select)

alt.hconcat(scatter_plot, bar_plot)

Ini akan membawa Anda ke perpustakaan visualisasi Altair. Ada banyak sekali fitur dan penyesuaian yang dapat Anda gunakan. Untuk referensi Anda dapat mengunjungi dokumentasi resmi. Selamat merencanakan!