Tüm Yazılar
KategoriSwiftUI
Okuma Süresi
10 dk
Yayın Tarihi
2026-10-15
Kelime Sayısı
1.479kelime

Kahveni hazırla - bu içerikli bir makale!

SwiftUI-Data-Visualization: Swift Charts üzerinde istatistik, finans ve canlı veri grafikleri

Özet

SwiftUI-Data-Visualization 2.0 neden Swift Charts üzerine kuruldu, analizini neden public tutuyor ve Swift Charts'ı durduran değerleri nasıl sınırlıyor.

  • Bu yazı paketin ne işe yaradığını, arkasındaki kararları, yayından hemen sonra bulunan hataları ve henüz yapmadığı şeyleri anlatıyor.
  • Her şeyi Canvas ile çizmek tam kontrol sağlardı, ama bu özelliklerin hepsini yeniden yazmak gerekirdi.
  • README'deki ekran görüntüleri bu çizimlerden geliyor. v2.0.1 tag'inde swift test 33 süitte 188 test koşturuyor; CI bunları macOS'ta ve bir iPhone simülatöründe çalıştırıyor.
  • Paketin geçmişi repoda görünüyor: Ağustos 2025'te açıldı, Şubat 2026'da 1.0.0 yayınlandı, Haziran 2026'da yer tutucu koda indirildi ve Ekim 2026'da 2.0.0 olarak yeniden kuruldu.
SwiftUI-Data-Visualization: Swift Charts üzerinde istatistik, finans ve canlı veri grafikleri

SwiftUI-Data-Visualization, iOS 17+ ve macOS 14+ üzerinde SwiftUI için grafik view'ları sunan bir

Swift paketi. 2.0.0 sürümüyle Swift Charts üzerine yeniden kuruldu; 2.0.1 de aynı gece, ilk

sürümün ele almadığı girdiler için düzeltmelerle geldi. Bu yazı paketin ne işe yaradığını,

arkasındaki kararları, yayından hemen sonra bulunan hataları ve henüz yapmadığı şeyleri anlatıyor.

İçindekiler


Problem

Swift Charts size mark'ları veriyor: LineMark, BarMark, PointMark, RectangleMark. Ham veriyi

doğru mark'lara dönüştürmek ise size kalıyor. Histogram bin kenarlarına ihtiyaç duyar. Box plot

çeyrekleri ve whisker'ları ister. Seri başına 50.000 okuma içeren bir zaman serisinin çizilmeden

önce küçültülmesi gerekir. Treemap bir yerleşim algoritması ister; radar grafiği ise Swift

Charts'ta bulunmayan kutupsal koordinatlara ihtiyaç duyar.

Daha az görünen ikinci bir sorun da veri. Grafikler çoğu zaman uygulamanın kendi üretmediği veriyi

çizer: sensör okumaları, fiyatlar, içe aktarılan dosyalar. Bir nan, bir sonsuz değer, binlerce

yıl uzaktaki bir tarih ya da Double.greatestFiniteMagnitude civarında bir değer uygulamayı

çökertmemeli.

Paket ikisini de ele alıyor. On grafik view'ı içeriyor: TimeSeriesChart, HistogramChart,

BoxPlotChart, ScatterChart, CandlestickChart, WaterfallChart, HeatmapChart, RadarChart,

TreemapChart ve LiveTickerChart. Arkalarındaki analizi de public yapıyor; aynı Histogram,

BoxPlotSummary ya da Downsampling kendi Chart'ınızda kullanılabiliyor. Hiçbir bağımlılığı yok.

Tasarım kararları ve alternatifler

Özel bir çizim motoru değil, Swift Charts. 1.0.0 sürümünün kendi LineChart, BarChart ve

PieChart view'ları vardı ve kaynak kodu güncel Xcode sürümleriyle derlenmiyordu. 2.0.0 bu

API'yi kaldırdı: düz çizgi, bar, alan ve pasta grafikleri için Swift Charts'ın kendi mark'ları

yeterli; eksenler, animasyon ve VoiceOver desteği de onlarla birlikte geliyor. Her şeyi Canvas ile

çizmek tam kontrol sağlardı, ama bu özelliklerin hepsini yeniden yazmak gerekirdi. Bu seçimin

bedeli, seçim ve kaydırma API'lerinin gerektirdiği iOS 17 ve macOS 14 alt sınırı.

Canvas yalnız Swift Charts'ın karşılamadığı yerde. On view'ın yedisi Swift Charts Chart'ı.

RadarChart, TreemapChart ve LiveTickerChart ise Canvas ya da düz view'larla çiziyor; çünkü

Swift Charts'ta kutupsal ya da treemap koordinatları yok, ekran yenileme hızında güncellenen bir

ticker'ı tek bir Canvas geçişinde çizmek de daha ucuz. Bu üçü Swift Charts'ın hazır verdiği

erişilebilirliği kaybediyor; bu yüzden her biri, veriyi VoiceOver'ın Audio Graph'larına anlatan bir

AXChartDescriptorRepresentable olan AudioGraphDescriptor ekliyor.

Analiz view'lardan ayrı. Analysis/, Layout/ ve Data/ klasörlerinde view kodu yok ve

tipler Sendable; main actor dışında çalışabiliyorlar. Her grafiğin çizmeden önce yaptığı

hazırlık (downsampling, whisker aralıkları, mum gövdesi genişlikleri, waterfall çubukları)

nonisolated static fonksiyonlarda duruyor ve testler bunları view kurmadan doğrudan çağırıyor.

Bilinen algoritmalar, kaynakta adıyla. NiceScale, Paul Heckbert'in "nice numbers" yöntemini

kullanıyor; tick'ler 1, 2 ya da 5 × 10ⁿ değerlerine oturuyor. Quantile hesabı Hyndman ve Fan'ın

type 7 tanımını izliyor; bu, Excel'in PERCENTILE.INC fonksiyonu ve NumPy'nin varsayılanıyla aynı,

yani sonuçlar insanların karşılaştırdığı araçlarla tutuyor. TreemapLayout, Bruls, Huizing ve van

Wijk'in squarified algoritması; dikdörtgenleri kareye yakın tutuyor. Slice-and-dice daha basit ama

ince şeritler üretiyor. TimeSeriesChart her seriyi Largest-Triangle-Three-Buckets ile 1.000

noktaya indiriyor. Her n'inci noktayı almak daha basit olurdu ama ani bir tepeyi atlayabilir; LTTB

ilk ve son noktayı tutuyor, her kovadan da komşularıyla en büyük üçgeni oluşturan noktayı seçiyor,

böylece eğrinin şekli korunuyor.

Hata fırlatmak yerine her girdiye cevap veren fonksiyonlar. Sonlu olmayan değerler atlanıyor,

boş veride istatistik sahte bir sıfır yerine nil dönüyor; tick sayısı, bin sayısı, ring

buffer'ın önceden ayırdığı bellek ve kaydırma pencereleri gibi değerlerin üst sınırı var. Alternatif olan throws ya da

precondition, ya her çağrı noktasına yük bindirir ya da tek bir bozuk okuma yüzünden uygulamayı

çökertir.

Canlı veri için bir value type ve tek bir gözlemlenebilir sınıf. RingBuffer, O(1) eklemeli

bir struct. Paketteki tek reference type olan LiveSeries onu main actor üzerinde @Observable

bir sınıf olarak sarıyor; LiveTickerChart Combine yerine SwiftUI observation ile güncelleniyor.

Renkler environment üzerinden. .chartPalette(_:) altındaki tüm grafiklerin paletini

belirliyor. Varsayılan .ocean; .colorblindSafe ise Okabe–Ito renklerini kullanıyor.

Ne bozuldu: sonlu değerler ve aynı tarihli mumlar

2.0.0'ın dokümanı grafiklerin her girdiyi kabul ettiğini söylüyordu. Testler nan, sonsuz değer

ve aşırı tarihleri kapsıyordu; aynı yeniden kurulumdaki daha önceki bir düzeltme (7009887), tarih

ekseni yaklaşık 1e19 saniyeye ulaştığında Swift Charts süreci durdurduğu için grafik tarihlerini

Date.distantPast...Date.distantFuture aralığına sınırlamıştı. Sonlu ama aşırı büyük değerler ise

test edilmemişti.

Bunların önemli olduğu ortaya çıktı. 9a67e99 commit'i hatayı kaydediyor: sayısal bir eksen

yaklaşık 1.6e308'den geniş bir aralığa yayıldığında ya da yaklaşık -1.5e308'in altına indiğinde

Swift Charts süreci "Double value cannot be converted to Int" hatasıyla durduruyordu. Bir zaman

serisinde tek bir -1.6e308 ya da bir scatter grafiğinde 1.7e308 ile -1 noktaları yetiyordu.

Swift Charts ekseni dışa doğru yuvarlıyor, sınır taşıyor ve Int'e çevriliyor. Yedi grafik bu

değerleri mark'larına olduğu gibi veriyordu.

Düzeltme, internal bir ChartValues.supported aralığı ekliyor: -1e307...1e307; hata veren ilk

aralıktan sekiz kat dar. Her grafik mark'a verdiği değeri bu aralığın sınırına çekiyor; readout'lar,

heatmap'te yazılan değerler ve VoiceOver etiketleri orijinal değeri koruyor. Yeni

"Extreme inputs: values" süiti on grafiğin hepsini yedi değer kümesiyle çiziyor; sınıra çekme olmadan

aynı fatal error ile duruyor.

Aynı pull request ikinci bir hatayı da düzeltti, bu kez CandlestickChart'ta. Candle.id mumun

tarihiydi ve grafik mumları Chart(_:)'e bu id ile veriyordu. Swift Charts id başına bir mark

çiziyor; aynı tarihli iki mumdan yalnız ilki çiziliyordu ve hiçbir uyarı yoktu. Bir render testi

bunu açıkça gösterdi: aynı gün A ve B mumlarını içeren grafik, yalnız A'yı içeren grafikle piksel

piksel aynıydı. 6b0c0b1 commit'i mumları konumlarıyla tanımlıyor:

swift
1// By position, not by `Candle.id`: candles that share a date would share an id, and
2// Swift Charts draws only one mark per id.
3Chart(Array(valid.enumerated()), id: \.offset) { _, candle in

Candle.id tarih olarak kaldı, yani public API değişmedi. Yeni test,

candlesThatShareADateAreAllDrawn, aynı tarihli iki mumu üçüncü bir mumun yanında çiziyor ve

ikisinden birini kaldırmanın görüntüyü değiştirdiğini doğruluyor.

Bu iki düzeltme, 1e308 civarındaki aralıklar için bir NiceScale düzeltmesi ve "1 outliers" diye

okunan bir VoiceOver etiketiyle birlikte #18 numaralı pull request ile 2.0.1 olarak çıktı; 2.0.0'dan

bir saat bile geçmeden. Ders geçmişte duruyor: 2.0.0'ın ele aldığı girdiler listesi eksikti, çünkü

bir girdi sınıfı (sonlu ama çok büyük) hiç test edilmemişti. Görüntünün gerçekten değişip

değişmediğine bakan bir render testi, "view derleniyor" testinin yakalamadığı hataları yakalıyor.

Kullanım

Paketi Swift Package Manager ile ekleyin:

swift
1dependencies: [
2 .package(url: "https://github.com/muhittincamdali/SwiftUI-Data-Visualization.git", from: "2.0.0")
3],
4targets: [
5 .target(name: "YourApp", dependencies: [
6 .product(name: "SwiftUIDataVisualization", package: "SwiftUI-Data-Visualization")
7 ])
8]

README'deki hızlı başlangıç, eksiksiz bir ContentView.swift:

swift
1import SwiftUI
2import SwiftUIDataVisualization
3 
4struct ContentView: View {
5 let steps = TimeSeries(
6 name: "Steps",
7 values: [4_200, 8_100, 6_900, 10_400, 7_800, 12_100, 9_300],
8 start: .now.addingTimeInterval(-6 * 86_400),
9 interval: 86_400
10 )
11 
12 var body: some View {
13 TimeSeriesChart(steps)
14 .frame(height: 240)
15 .padding()
16 }
17}

Histogram ve box plot içeren bir istatistik raporu:

swift
1struct LatencyReport: View {
2 let ios: [Double] = [112, 98, 130, 101, 145, 120, 99, 180, 104, 117, 125, 133, 230, 108, 121]
3 let android: [Double] = [140, 151, 128, 160, 149, 171, 138, 155, 162, 147, 158, 133, 166, 152]
4 
5 var body: some View {
6 VStack(spacing: 24) {
7 HistogramChart(values: ios + android, binning: .width(25), valueLabel: "Latency (ms)")
8 .frame(height: 180)
9 BoxPlotChart([
10 .init(name: "iOS", values: ios),
11 .init(name: "Android", values: android),
12 ], valueLabel: "Latency (ms)")
13 .frame(height: 200)
14 }
15 .padding()
16 }
17}

binning verilmezse histogram, Sturges ya da Freedman–Diaconis kuralından hangisi daha çok bin

veriyorsa onu seçiyor; box plot da çeyrekler açıklığının 1,5 katından daha uzaktaki değerleri aykırı değer

olarak işaretliyor.

Bu örnekler yalnızca doküman değil. README bunları Examples/ChartGallery/ChartGallery/ReadmeSamples.swift

dosyasından kopyalıyor; ChartGallery örnek uygulaması bu dosyayı derliyor, test target'ı da aynı

dosyayı bir symlink üzerinden derleyip her örneği açık ve koyu temada çiziyor. README'deki ekran

görüntüleri bu çizimlerden geliyor. v2.0.1 tag'inde swift test 33 süitte 188 test koşturuyor; CI

bunları macOS'ta ve bir iPhone simülatöründe çalıştırıyor.

Sınırlar

  • Platformlar: yalnız iOS 17+ ve macOS 14+. visionOS yol haritasında, ama test edilmedi ve

açılmadı; watchOS ve tvOS desteklenmiyor.

  • Araç zinciri: Swift 6.2 tools ve Xcode 26 ya da üstü. CI, GitHub'ın macos-26 runner

imajındaki varsayılan Xcode ile derliyor; başka Xcode sürümleri denenmedi.

  • Değer ve tarih sınırları ölçüm, şartname değil. -1e307...1e307 ve tarih aralığı Swift

Charts'ın bugünkü davranışından çıkarıldı. Gelecekteki bir işletim sistemi bunu değiştirebilir;

o durumda aşırı girdi süitleri kırılıp bunu gösterir.

  • Sınıra çekme görünür. ±1e307'nin ötesindeki değerler o sınırda çiziliyor; bu yüzden böyle iki

değer ekranda ayırt edilemiyor, ama readout ve VoiceOver gerçek değeri söylüyor.

  • Benchmark yok. 1.000 noktalık varsayılanın ve kaydırma penceresi sınırının gerekçesi var,

ama paketin bir benchmark süiti yok; eski Benchmarks/ klasörü hiçbir benchmark'ın üretmediği

sayıları raporluyordu ve yeniden kurulumda kaldırıldı.

  • Taşınmayan grafikler: SwiftUI-Charts-Pro'daki Sankey, chord, violin, parallel coordinates ve

word cloud taşınmadı. Her biri TreemapLayout ve Histogram düzeyinde testlerle gelmesi gereken

kendi yerleşim ya da kestirim algoritmasını istiyor. Gauge, bubble, funnel, Gantt ve sunburst ise

SwiftUI'ın Gauge view'ı ya da birkaç Swift Charts mark'ı zaten karşıladığı için dışarıda kaldı.

  • Zaman ekseninde pinch ile yakınlaştırma henüz yok; paketin Swift Package Index'te

listelenmesiyle birlikte yol haritasında.

Paketin geçmişi repoda görünüyor: Ağustos 2025'te açıldı, Şubat 2026'da 1.0.0 yayınlandı, Haziran

2026'da yer tutucu koda indirildi ve Ekim 2026'da 2.0.0 olarak yeniden kuruldu. CHANGELOG, 1.0.0'ın

güncel Xcode sürümleriyle derlenmediğini açıkça yazıyor.

Kaynak kod: github.com/muhittincamdali/SwiftUI-Data-Visualization

Etiketler

#swiftui#swift-charts#data-visualization#statistics#accessibility#swift-package
Muhittin Çamdalı

Muhittin Çamdalı

Senior Mobile Engineer

12+ yıllık deneyime sahip Senior Mobile Engineer. iOS, Flutter ve React Native ile mobil ürünler geliştiriyorum; full-stack ve AI-native çalışıyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Onay e-postasındaki bağlantıyı açıp “Aboneliğimi onayla” düğmesine bastığında aboneliğin başlar. Bültende açılma/tıklama istatistikleri tutulur; dilediğin an tek tıkla ayrılabilirsin. Gizlilik

Paylaş

İlgili İçerik