스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Swift Charts: 벡터화된 플롯과 함수 플롯
플롯의 반전! 함수와 벡터화된 플롯을 사용하여 앱에서 수학적 함수와 대규모 데이터세트를 근사하게 표현하도록 차트를 렌터링하는 방법을 알아보세요. Swift Charts는 기체 역학, 자기, 고차장론에서 일반적으로 사용되는 함수를 표시하는 것은 물론 대형 대화식 열 지도도 구현할 수 있습니다.
챕터
- 0:00 - Introduction
- 1:01 - Function plots
- 6:48 - Vectorized plots
- 11:27 - Best practices
리소스
관련 비디오
WWDC23
WWDC22
-
다운로드
안녕하세요, 저는 Apollo입니다 Swift Charts의 최신 기능을 소개하겠습니다 Swift Charts를 사용하면 SwiftUI를 활용하여 유익하고, 사용이 쉽고, 흥미로운 시각 자료를 생성할 수 있습니다
이번 릴리즈에서 선보이는 새로운 차트는 날씨 추세를 보여 주고
기분과 활력 징후를 추적하며
수학 노트의 그래프 기능을 제공합니다
맞습니다!
이제 Swift Charts를 사용하면 앱에 수학 함수를 플롯 작업하며 데이터 이상의 요소를 시각화할 수 있습니다
Swift Charts에는 이제 대규모 데이터 세트를 더 효율적으로 시각화하도록 지원하는 벡터화된 플로팅 API도 있습니다 이 비디오는 Swift Charts의 흥미롭고 새로운 각 기능을 자세히 설명하기 위해 마련되었습니다 다음 두 개의 새로운 API를 도입하는 함수 플롯으로 시작하겠습니다
LinePlot은 단일 함수를 시각화하고 AreaPlot은 두 함수 사이의 영역을 채웁니다 함수 플롯이 데이터 분석에 어떻게 도움이 되는지 살펴보겠습니다
미국 지질 조사국의 데이터 세트를 사용하여 미국 인접 지역에 있는 대규모 태양광 에너지 프로젝트를 조사했습니다
데이터 포인트에 대한 ForEach와 각 요소에 대한 BarMark를 사용하여 태양광 패널의 용량 밀도를 시각화하는 히스토그램을 만들었습니다 아시나요? 이 히스토그램은 그 용량 밀도가 정규 분포일 수 있음을 나타냅니다 새로운 함수 플롯 API를 사용하여 정규 분포를 그려서 비교해 보겠습니다
정규 분포 곡선의 점을 계산하는 함수를 정의했으며
새로운 LinePlot API를 사용하여 이를 그릴 수 있습니다 이는 Double을 취해 Double을 반환하는 클로저를 허용하므로 미리 계산된 평균과 표준 편차를 사용하여 함수를 호출할 수 있습니다
Swift Charts의 기본은 누구나 데이터 시각화를 이용할 수 있어야 한다는 것입니다 Swift Charts를 사용하면 차트에 기본적으로 액세스할 수 있습니다
VoiceOver를 사용하여 차트를 설명할 수 있습니다 “x축은 용량 밀도이고 y축은 확률입니다 두 개의 데이터 시리즈가 있습니다” 오디오 그래프는 함수 플롯에서도 작동합니다
“완료되었습니다”
좋아요! SwiftUI와 마찬가지로 한정자를 사용하여 함수 모양을 맞춤화할 수 있습니다
여기에서 LinePlot의 기본 색상이 막대와 동일하기 때문에 다른 foregroundStyle을 사용하여 함수 플롯의 색상을 맞춤화하는 것이 좋습니다
이제 훨씬 좋아 보이네요 하지만 좀 더 눈에 띄게 하기 위해 곡선 아래 영역을 채우고 싶네요 그러려면 LinePlot만 AreaPlot으로 변경하면 됩니다
그런 다음 대비를 높이기 위해 불투명도로 AreaPlot의 맞춤화 수준을 높여 읽기 쉽게 만들 수 있습니다
이것이 간단한 수학 함수를 그리는 방법입니다 하지만 Swift 차트를 사용하면 쉽게 고급 함수 플롯을 만들 수 있습니다
예를 들어 AreaPlot은 곡선 아래의 영역을 시각화할 수 있을 뿐만 아니라 주어진 입력 x에 대해 yStart 및 yEnd의 튜플을 반환하여 두 함수 사이의 영역을 시각화하는 데에도 사용할 수 있습니다
데이터 시각화와 달리 함수는 허용되는 x 값의 범위가 제한되지 않습니다 기본적으로 Swift Charts는 함수를 샘플링하여 자동으로 영역을 유추합니다
하지만 X 척도와 Y 척도를 설정하여 관심이 있는 함수 부분만 포함하도록 차트의 전체 경계를 맞춤화할 수 있습니다
함수 플롯 자체의 영역을 제한하는 기능도 있습니다
AreaPlot의 샘플링 영역을 제한하여 이제 차트에는 이 기능의 중간 부분만 포함됩니다
Swift Charts는 매개변수 함수의 플롯 작업도 지원합니다
이것은 x 및 y가 세 번째 변수 T로 정의되는 매개변수 함수입니다 플롯 작업을 해 보겠습니다
동일한 LinePlot API를 사용하여 Swift Charts에서 매개변수 함수를 그래프로 표시할 수 있지만 주어진 t 값에 대해 x 및 y 값을 모두 반환합니다 하트를 그렸군요
이제 조각별 함수를 처리하는 방법을 살펴보겠습니다
경우에 따라 조각별 함수에는 해당 도메인 내의 특정 값에 대해 출력이 없을 수 있습니다
이러한 경우 .nan을 반환하여 해당 입력 값 x에 대한 숫자가 없음을 Swift Charts에 알릴 수 있습니다
다른 경우에는 x가 0일 때 x에 대해 1을 평가하는 경우와 같이 코드가 특정 x 값을 트래핑할 수 있습니다
마찬가지로 .nan을 반환하여 특수 값을 처리해야 합니다
이것이 전체 수학 함수를 단일 엔티티로 처리하는 Line Plot 및 Area Plot을 사용한 함수 플롯 작업입니다 그러나 플롯 API는 함수 외에 다른 곳에도 유용합니다
더 큰 데이터 세트를 시각화하는 것이 더 편리하고 효율적일 수 있습니다
따라서 다른 모든 마크 유형에 대한 플롯 API 변형도 추가했습니다
이렇게 벡터화된 플롯 API는 전체 모음을 병렬로 처리하여 분류 모델에 대한 산포도 또는 변환기 언어 모델에서 자기주의를 시각화하는 히트맵과 같은 광범위한 데이터 시각화를 그릴 수 있습니다 하지만 더 복잡한 내용을 다루기 전에 Mark API를 사용하여 차트를 선언하는 방법을 검토하겠습니다
Mark는 매우 유연하여 적용할 한정자를 선택하는 것부터 사용할 마크의 종류까지 개별 데이터 포인트의 스타일을 다르게 지정할 수 있습니다
그러나 대부분 이 정도 수준의 맞춤화까지는 필요하지 않습니다 X, Y, foregroundStyle 및 기타 시각적 속성에 대해 동일한 요소 속성을 사용하여 전체 데이터 포인트 모음의 스타일을 동질적으로 지정하는 것이 일반적입니다
반면에 새로운 RectanglePlot과 같은 새로운 Vectorized Plot API를 사용하면 Swift Charts가 더 큰 데이터 모음을 더 효율적으로 처리할 수 있습니다 벡터화된 플롯의 예를 위해 태양광 패널 데이터 세트로 돌아가겠습니다
앱에 모든 태양광 패널 설치의 시각화를 추가하려고 합니다
이 차트의 모든 지점에 대해 동일한 방식으로 맞춤화하려고 합니다 크기는 용량에 따라 결정되며
패널의 축 유형에 따라 색상이 다르게 표시됩니다
데이터 세트에는 경도와 위도가 포함된 원시 GPS 좌표가 있지만 Albers 투영을 적용하여 평평한 표면에 점을 표시하고 싶습니다
이 변환을 즉시 수행하기 위해 확장에 계산된 속성을 추가할 수 있지만 벡터화된 플롯을 최대한 활용하기 위해 대신 저장된 속성으로 추가하겠습니다
저장된 속성을 사용하면 Swift Charts는 모든 데이터 포인트에 대해 getter를 호출하는 대신 일정한 메모리 오프셋을 사용하여 모든 데이터 포인트의 x 및 y 값에 접근할 수 있습니다
새로운 PointPlot API는 전체 데이터 모음을 사용해 플롯 작업합니다
플롯에 있는 모든 점의 x 및 y 값에 대해 레이블과 함께 동일한 .value 구문을 사용할 수 있습니다 그리고 DataPoint 구조의 저장된 속성 x, y에 KeyPath를 사용할 수 있습니다
이전에 SwiftUI를 사용한 적이 있다면 이미 KeyPath를 사용해 보셨을 겁니다 KeyPath를 사용하면 Swift Charts에서 데이터 세트를 반복하지 않고도 모든 포인트의 스타일을 지정할 수 있습니다
벡터화된 플롯의 한정자도 KeyPath를 사용합니다
symbolSize를 사용하여 각 포인트의 크기가 각 태양광 패널 용량을 나타내도록 했습니다 마찬가지로 태양광 패널의 축 유형에 KeyPath를 사용하여 각 지점의 색상을 맞춤화했습니다
유사한 수정에 자주 사용되는 다른 모든 한정자도 KeyPath 매개변수를 지원합니다
이 앱을 공간 컴퓨팅 기능을 갖춘 Apple Vision Pro에서 보면 아주 멋집니다 왼쪽의 벡터화된 플롯은 부드럽게 애니메이션 처리되며 막대 차트를 문지르면 대시보드의 모든 차트가 동시에 업데이트됩니다
핀치 앤 드래그로 방금 추가된 벡터화된 플롯을 자세히 살펴보고 각 태양광 패널 설치에 대해 자세히 알아볼 수 있으며 이전에 생성한 정규 분포 플롯을 한눈에 살펴볼 수 있습니다
이것이 벡터화된 플롯입니다 이제 벡터화된 플롯과 Mark가 어떻게 상호 보완되는지 궁금하실 겁니다
전체 플롯이 같은 한정자 및 속성으로 맞춤화된 대규모 데이터 세트에서는 벡터화된 플롯을 사용하세요
데이터 포인트 수가 적지만 개별 마크 유형 및 한정자로 각 요소를 맞춤화해야 하거나 zIndex를 사용한
복잡한 레이어링이 필요하다면 Mark API를 사용하세요
벡터화된 플롯을 사용할 때 사용할 스타일별로 데이터 모음을 그룹화하면 Swift Charts가 스타일을 바꾸는 횟수를 줄일 수 있습니다
계산된 속성을 저장된 속성으로 변환하는 등 렌더링 중에 다른 계산을 피하는 것도 도움이 될 수 있습니다
사용할 몇 가지 고유한 스타일이나 차트의 모든 범위를 이미 알고 있는 경우 해당 스타일을 지정하면 차트가 더 효율적으로 렌더링됩니다
끝으로 어떤 스타일 맞춤화는 데이터 포인트가 대규모라면 보통은 눈에 띄지 않으므로 해당 항목을 완전히 건너뛸 수 있습니다
이것이 Swift Charts에서 새롭게 벡터화된 플롯과 함수 플롯입니다
이 새로운 기능을 활용하여 한층 뛰어난 시각화를 구현하세요 샘플 프로젝트를 다운로드하여 상호작용을 추가하는 방법 등 함수 플롯의 더 많은 예를 확인하세요 Swift 차트를 처음 사용한다면 이전 비디오부터 확인해 보세요
감사합니다 여러분의 결과물이 매우 기대됩니다
-
-
1:43 - Histogram that shows distribution of capacity density
Chart { ForEach(bins) { bin in BarMark( x: .value("Capacity density", bin.range), y: .value("Probability", bin.probability) ) } }
-
2:18 - Visualize function with LinePlot
Chart { LinePlot( x: "Capacity density", y: "Probability" ) { x in // (Double) -> Double normalDistribution( x, mean: mean, standardDeviation: standardDeviation ) } }
-
3:36 - Customize function plot with modifiers
Chart { LinePlot( x: "Capacity density", y: "Probability" ) { x in normalDistribution(x, ...) } .foregroundStyle(.gray }
-
3:57 - Visualize area under a curve with AreaPlot
Chart { AreaPlot( x: "Capacity density", y: "Probability" ) { x in normalDistribution(x, ...) } .foregroundStyle(.gray) .opacity(0.2) }
-
4:21 - Visualize area between curves with AreaPlot
Chart { AreaPlot( x: "x", yStart: "cos(x)", yEnd: "sin(x)" ) { x in (yStart: cos(x / 180 * .pi), yEnd: sin(x / 180 * .pi)) } }
-
4:59 - Specify domain for function plots
Chart { AreaPlot( x: "x", yStart: "cos(x)", yEnd: "sin(x)" ) { x in (yStart: cos(x / 180 * .pi), yEnd: sin(x / 180 * .pi)) } } .chartXScale(domain: -315...225) .chartYScale(domain: -5...5)
-
5:18 - Specify sampling domain for function plots
Chart { AreaPlot( x: "x", yStart: "cos(x)", yEnd: "sin(x)", domain: -135...45 ) { x in (yStart: cos(x / 180 * .pi), yEnd: sin(x / 180 * .pi)) } } .chartXScale(domain: -315...225) .chartYScale(domain: -5...5)
-
5:55 - Visualize parametric functions
Chart { LinePlot( x: "x", y: "y", t: "t", domain: -.pi ... .pi ) { t in let x = sqrt(2) * pow(sin(t), 3) let y = cos(t) * (2 - cos(t) - pow(cos(t), 2)) return (x, y) } } .chartXScale(domain: -3...3) .chartYScale(domain: -4...2)
-
6:40 - Use Double.nan to represent no value
Chart { LinePlot(x: "x", y: "1 / x") { x in guard x != 0 else { return .nan } return 1 / x } } .chartXScale(domain: -10...10) .chartYScale(domain: -10...10)
-
7:43 - Highly customized Chart
Chart { ForEach(model.data) { if $0.capacityDensity > 0.0001 { RectangleMark( x: .value("Longitude", $0.x), y: .value("Latitude", $0.y) ) .foregroundStyle(by: .value("Axis type", $0.axisType)) } else { PointMark( x: .value("Longitude", $0.x), y: .value("Latitude", $0.y) ) .opacity(0.5) } } }
-
8:00 - Homogeneously styled Chart
Chart { ForEach(model.data) { RectangleMark( x: .value("Longitude", $0.x), y: .value("Latitude", $0.y) ) .foregroundStyle(by: .value("Axis type", $0.panelAxisType)) .opacity($0.capacityDensity) } }
-
8:23 - Vectorized plot for homogeneously styled chart
Chart { RectanglePlot( model.data, x: .value("Longitude", \.x), y: .value("Latitude", \.y) ) .foregroundStyle(by: .value("Axis type", \.panelAxisType)) .opacity(\.capacityDensity) }
-
9:42 - Vectorized point plot API
Chart { PointPlot( model.data, x: .value("Longitude", \.x), y: .value("Latitude", \.y) ) }
-
10:26 - Vectorized plot modifiers
Chart { PointPlot( model.data, x: .value("Longitude", \.x), y: .value("Latitude", \.y) ) .symbolSize(by: .value("Capacity", \.capacity)) .foregroundStyle( by: .value("Axis type", \.panelAxisType) ) }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.