The seaborn.objects interface(seaborn객체 인터페이스)
Building and displaying the plot(플롯 작성과 표시)
앞선 seaborn.objects interface 튜토리얼에서는 하나의 마크만 있는 서브플롯만 만들었다. 그러나 두개 이상도 가능하다!
Adding multiple layers(여러 레이어 추가)
더 복잡한 단일 서브폴롯은 Plot.add()를 반복해서 호출해 생성할 수 있다! 호출될 때마다, 플롯의 층을 정의한다. 예를들면, Dots를 이용해 산점도를 추가하고 회기 적합을 추가할 수 있다!
tips데이터를 써서...
x에 총 계산금액, y에 팁을 Plot에 넣어준뒤...
.add(so.Dots())로 산점도를 생성하고...
.add(so.Line(). so.PolyFit())으로 회기 적합 모형을 넣어준다!
import seaborn.objects as so
tips = sns.load_dataset("tips")
(
so.Plot(tips, x="total_bill", y="tip")
.add(so.Dots())
.add(so.Line(), so.PolyFit())
)
이렇게 산점도 위에 회기 적합 모형이 그려졌다!
Plot에서 정의된 변수 매핑은 모든 계층에서 사용된다!
위의 코드에 Plot에서 color='time'을 추가해주면...
(
so.Plot(tips, x="total_bill", y="tip", color="time")
.add(so.Dots())
.add(so.Line(), so.PolyFit())
)
이렇게 회기선이 color에 넣어준 시간별로 그려진다!
Layer-specific mappings(레이어 특정 매핑)
특정 레이어에만 사용되도록 매핑을 정의할 수 있다. 매핑을 사용하고 싶은 레이어에 대한 Plot.add에 매핑을 정의하면 된다!
만약 위의 그림에서 산점도만 컬러별로 나누고 싶으면...
이렇게 color='time'을 so.Dots()가 있는 .add()에 넣으면...
(
so.Plot(tips, x="total_bill", y="tip")
.add(so.Dots(), color="time")
.add(so.Line(color=".2"), so.PolyFit())
)
이렇게 산점도만 시간별로 색상이 나뉘고...
회기선은 하나로 그려진다!(색상은 0.2로 검은색에 가깝다)
또 다른 방법은, 전체 플롯에 대해 레이어를 정의 한 다음, 특정 레이어에서 해당 변수에 None으로 설정해줌으로서 없애는 것이다!
(
so.Plot(tips, x="total_bill", y="tip", color="time")
.add(so.Dots())
.add(so.Line(color=".2"), so.PolyFit(), color=None)
)
이렇게 똑같은 그림이 그려진다!
요약하자면... mark속성의 값을 명시하는 3가지 방법이 있다!
1. 모든 계층에 변수를 매핑
2. 특정 계층에 변수를 매핑
3. 직접 속성을 설정
그림으로 표현하면 아래와 같다!
이미지 출처 : https://seaborn.pydata.org/_images/objects_interface_48_0.svg
Faceting and pairing subplots(서프플롯 팻싱과 페어링)
seaborn 그림 수준 함수처럼 Plot인터페이스는 여러 패싯을 가지거나 데이터의 부분집합을 포함한 서브플롯을 가진 그림을 생성할 수 있다! Plot.facet() 메서드로 할 수 있다!
펭귄데이터를 이용해서 x는 날개길이로 해서 히스토그램을 그려볼건데...
.facet('species')메서드를 통해 종별 날개길이의 히스토그램을 보자!
penguins = sns.load_dataset("penguins")
(
so.Plot(penguins, x="flipper_length_mm")
.facet("species")
.add(so.Bars(), so.Hist())
)
이렇게 종별로 서브플롯이 그려진다!
열과 행을 정의하는데 쓰이는 변수를 넣어서 Plot.facet()을 호출해보자!
facet안에 열은 종 행은 성별로 해서 그려보면...
(
so.Plot(penguins, x="flipper_length_mm")
.facet(col="species", row="sex")
.add(so.Bars(), so.Hist())
)
이렇게 열은 종, 행은 성별 별로 히스토그램이 그려졌다!
다른 차원에 걸쳐 래핑하여 수준 수가 더 많은 변수를 사용하여 패싯할 수 있다!
healthexp 데이터를 사용해서 라인그래프를 그릴건데...
x는 연도, y는 기대수명 라인그래프를
.facet(col='Country', wrap=3)으로 그려보면...
healthexp = sns.load_dataset("healthexp")
(
so.Plot(healthexp, x="Year", y="Life_Expectancy")
.facet(col="Country", wrap=3)
.add(so.Line())
)
이렇게 한 행에 3개씩 그래프가 그려진다!
명시적으로 제외하지 않으면 모든 레이어가 페싯되는데... 각 서브플롯의 추가적인 맥락을 제공하는데 유용하다!(명시적으로 제외하면...)
이렇게 위의 그래프에서 선을 좀 굵게해주고...(linewidth=3으로)
.add(so.Line(alpha=.3), group="Country", col=None)으로 한 그래프 안에 모든 나라별 그래프를 흐리게 설정...
(
so.Plot(healthexp, x="Year", y="Life_Expectancy")
.facet("Country", wrap=3)
.add(so.Line(alpha=.3), group="Country", col=None)
.add(so.Line(linewidth=3))
)
이렇게 해당 나라의 선만 진하게 그려진 것을 볼 수 있다!
서브플롯을 그리는 다른 방법은 Plot.pair()이다! seaborn.PairGrid와 같이, Plot.pair()는 모든 데이터를각 서브플롯에 그리는데... x나 y좌표에 대해 다른 변수를 사용한다.
펭귄 데이터로 y는 몸무게...(종벌)로 산점도를 그릴건데...
x는 각각 부리 길이와 깊이로 subplot을 그려보면...
(
so.Plot(penguins, y="body_mass_g", color="species")
.pair(x=["bill_length_mm", "bill_depth_mm"])
.add(so.Dots())
)
이렇게 부리 길이, 부리 깊이로 나뉘어 서브플롯이 그려진다!
연산이 서브플롯을 다른 차원으로 추가하면 facet과 pair을 같이 쓰는 것도 가능하다!
.facet(row='sex')로 성별로 행을 나눠주면...
(
so.Plot(penguins, y="body_mass_g", color="species")
.pair(x=["bill_length_mm", "bill_depth_mm"])
.facet(row="sex")
.add(so.Dots())
)
이렇게 열별로는 부리 길이, 부리 깊이로 나뉘고, 행별로는 성별로 나뉜다!
Integrating with matplotlib(matplotlib과의 통합)
다수의 서브플롯이 Plot.facet()과 Plot.pair()가 제공하는 것 이상의 더 복잡한 구조를 가진 그림으로 나타나길 원하는 경우가 있다. 현재 해결책은 그림 셋업을 matplotlib에 위임하고 matplotlib객체를 제공하는 것인데... 이때 Plot()은 Plot.on() 메서드와 함께 사용해야 한다! Plot.on()의 객체 matplotlib.Axes, matplotlib.figure.Figure이나 matplotlib.figure.SubFigure 중 하나일 수 있는데... matplotlib.figure.SubFigure가 맞춤 서브플롯 구성을 만들기에 가장 유용하다!
matplotlib을 import해주고...
그림크기를 맞춰 준다음에...
.subfigures(1, 2)로 한 행에 2개의 그림이 나오게 하고...
.on(sf1)로 산점도, .on(sf2)로 히스토그램을 그린다!
import matplotlib as mpl
f = mpl.figure.Figure(figsize=(8, 4))
sf1, sf2 = f.subfigures(1, 2)
(
so.Plot(penguins, x="body_mass_g", y="flipper_length_mm")
.add(so.Dots())
.on(sf1)
.plot()
)
(
so.Plot(penguins, x="body_mass_g")
.facet(row="sex")
.add(so.Bars(), so.Hist())
.on(sf2)
.plot()
)
이렇게 종류가 다른 그래프를 한 그림에 그릴 수 있다!
Building and displaying the plot(플롯 만들기와 표시)
중요한 점이 있는데... Plot 메서드는 호출된 객체를 복제하고 바로 객체를 업데이트하는 대신 복제본을 반환한다! 즉 공통의 플롯 사양을 정의하고 플롯 사양에 대한 변형을 만들 수 있다!
기본 사양을...
이렇게 만들어 보자!(데이터는 healthexp로 했다!)
x는 연도, y는 Spending_USD, color는 국적으로 했다!
p = so.Plot(healthexp, "Year", "Spending_USD", color="Country")
라인 플롯을 그려보면...
p.add(so.Line())
이렇게 바로 그려지고...
stacked area플롯을 그려보면...
p.add(so.Area(), so.Stack())
이렇다!
라인그래프를 서브플롯으로 그려보면...
p.facet(col="Country", wrap=3).add(so.Line())
이렇다!
Plot메서드는 완전히 선언적이다! Plot메서드를 호출해서 플롯 사양을 업데이트해도 아무 그림도 그리지 않는다. 그 결과 Plot메서드가 어느 순서로든 호출될 수 있고 대부분 여러 번 호출될 수 있다!
그럼 언제 플롯이 렌더링될까? Plot은 노트북환경에서의 사용에 최적화되어있다! 플롯 렌더링은 Plot이 주피터 REPL에 표시될 때 자동으로 작동된다! 이것은 바로 위 예제에서 REPL에 표시되게 하지 않고 p라는 변수에 할당했을 때 아무것도 보지 못한 이유이다!
노트북에서 플롯을 보려면 셀의 마지막 줄에서 리턴해주거나 주피터 내장 객체 display함수를 호출하면 된다. 노트북 통합은 matplotlib.pyplot을 완전히 우회하지만, Plot.show()를 호출함으로서 다른 문맥에서 그림을 표시해주는 장치로 사용할수 있다!
이렇게 .show()를 붙여주면...
p1에 저장되었지만...
p = (
so.Plot(healthexp, "Year", "Spending_USD", color="Country")
.add(so.Area(), so.Stack())
.show()
)
그래프를 표시할 수 있다!
또 Plot.save()를 통해 플롯을 파일이나 버퍼로 저장할 수 있다!
참고사이트
https://seaborn.pydata.org/tutorial/objects_interface.html#building-and-displaying-the-plot
댓글