21.4 그래프 영역 (mar, oma, , mfrow, mfcol, layout)

그래프 영역은 크게 (1) 플롯 영역 (plot area), (2) 내부 마진 영역 (inner margin area), (3) 외부 마진 영역(outer margin area) 로 구분할 수 있습니다. 아래의 예시 그래프에 각 영역의 위치에 text 로 표기를 해보았습니다.

21.4.1 플롯 영역 (plot area), 내부 마진 영역 (inner margin area)

  1. 플롯 영역 (plot area)은 점이든 선이든 기호가 그려지는 영역입니다.

  2. 내부 마진 영역 (inner margin area)는 플롯 영역을 감싸고 있는 4개 모서리 부분의 마진입니다. 하단 부분이 1번, 왼쪽 부분이 2번, 상단부분이 3번, 오른쪽 부분이 4번이며, 순서대로 내부 마진 영역의 디폴트 값은 c(5.1, 4.1, 4.1, 2.1) 입니다. 하단은 x축 레이블, 왼쪽은 y축 레이블, 상단은 제목이 들어가는 영역입니다. 그래서 기본 값의 마진 숫자가 큰 반면에, 오른쪽은 보통은 레이블이 없으므로 디폴트 마진 값이 타 영역의 반밖에 되지 않습니다.

##------------------------------------------- 
## 그래프 영역과 내부/외부 마진
##------------------------------------------- 
 
library(MASS) 
# to use Cars93 dataframe 
 
# 플롯 영역과 내부 마진 영역의 기본값으로 설정되어 있는대로 그래프를 작성합니다.
# 기본 값 내부 마진 영역 : c(5.1, 4.1, 4.1, 2.1)
 
plot(MPG.highway ~ Weight, Cars93, type="p", 
     xlab = "Inner Margin Area 1", 
     ylab = "Inner Margin Area 2",      
     main = "Inner Margin Area 3") 

# 저수준 함수들을 이용하여 영역을 표시해 줍니다.
mtext("내부 마진 영역 4", side = 4, col = "blue") 
text(3000, 35, cex = 3, labels = "플롯 영역", pos = 3, col = "blue")

21.4.2 외부 마진 영역 (outer margin area)

외부 마진 영역은 내부 마진 영역의 바깥 쪽을 둘러싸는 마진 영역입니다. 내부 마진 영역과 위치 순서는 똑같이 하단 부분이 1번, 왼쪽 부분이 2번, 상단 부분이 3번, 오른쪽 부분이 4번입니다. 1번, 2번, 3번, 4번 별로 디폴트 마진 값은 c(0, 0, 0, 0) 입니다. 즉 위의 예의 경우 외부 마진(outer margin) 을 별도로 지정해주지 않았으므로 디폴트 값이 적용되어 외부 마진(outer margin)은 모두 ‘0’ 으로 없는 셈입니다.

외부 마진 영역은 위의 예처럼 1개짜리 그래프에서는 별 쓸모가 없습니다만 (그냥 내부 마진 영역으로 cover 되기 때문입니다), 그래프 영역을 분할해서 2개 이상의 그래프를 하나의 그래프에 결합할 경우 유용하게 사용할 수 있습니다. 개별 그래프에서는 내부 마진 영역에 제목, x축 레이블, y축 레이블을 적고, 2개 이상의 개별 그래프들을 모두 포괄하는 대제목 (mega title)을 적고자 할 때 외부 마진 영역에 적으면 딱 좋습니다.

아래에 1개의 행, 2개의 열로 영역을 분할(mfrow = )한 경우 외부 마진 영역 설정(oma = ), 내부 마진 영역 설정(mar = ) 함수의 예를 들어보겠습니다. 외부 마진 부분은 파란색으로 알아보기 쉽게 위치 표시를 했습니다.

참고로, op <- par(no.readonly = TRUE)로 디폴트 par 값을 미리 할당해 두면, 나중에 par값 조정 다 끝나고 원래의 디폴트 값으로 되돌아오고자 할 때 par(op)를 실행시키면 되므로 매우 편리합니다.

library(MASS)

## 내부 마진 영역과 외부 마진 영역
# par의 기본 설정 값을 저장합니다.
op <- par(no.readonly = TRUE) 
 
# par() 함수 옵션을 변경합니다.
par(mfrow = c(1,2),                       # 1행 2열로 프레임을 분할합니다.
    mar = c(4, 3, 3, 1),                  # 내부 마진을 설정합니다.
    oma = c(0.5, 0.5, 2, 0.5))            # 외부 마진을 설정합니다.
 
# 플롯 영역, 내부 마진 영역, 외부 마진 영역
plot(MPG.highway ~ Weight, Cars93, type="p",
     xlab = "Inner Margin Area",
     main = "Inner Margin Area") 
 
plot(MPG.highway ~ Horsepower, Cars93, type="p",
     xlab = "Inner Margin Area",
     main = "Inner Margin Area") 

# 저수준 함수로 텍스트를 표시합니다.
mtext("Outer Margin Area", outer = TRUE, cex = 2, col = "blue")   # outer = TRUE : 외부 마진 영역

# par를 초기 설정값으로 환원합니다.
par(op)

21.4.3 영역 분할/결합 방법 1

2개 이상의 다수의 그래프를 결합하는 방법에는 par() 함수와 layout() 함수의 2가지 방법이 있습니다.

먼저 par() 방법을 살펴보면, par(mfrow = ), par(mfcol = ) 의 2가지 모수 설정 방법이 있습니다. mfrowmfcol 은 아래의 말을 줄여 쓴 말입니다.

  • mfrow : 행 우선의 복수 플롯의 수

  • mfcol : 열 우선의 복수 플롯의 수

par(mfrow = c(4, 2)) 은 복수의 플롯 작성할 때 프레임을 4행 2열로 분할하여 한 프레임에 표시하라는 의미입니다.

그래프가 그려지는 순서를 화살표로 표시를 해두었는데요, 상단 왼쪽에서 시작해서 오른쪽으로 지그재그로 하단으로 내려가면서 그래프가 순차적으로 그려집니다.

library(MASS)

# par의 기본 설정 값을 저장합니다.
op <- par(no.readonly = TRUE) 

##-- par(mfrow = ): 행 우선의 복수 플롯의 수
par(mfrow = c(4, 2),                             # 4행 2열로 프레임을 분할합니다
    mar = c(4, 3, 3, 1),                         # 내부 마진을 설정합니다.
    oma = c(0.5, 0.5, 2, 0.5))                   # 외부 마진을 설정합니다.

plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 1") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 2") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 3") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 4") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 5") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 6") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 7") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 8") 
 
mtext("par(mfrow = c(4, 2)", outer = TRUE, cex = 2, col = "blue")

# par를 초기 설정값으로 환원합니다.
par(op)

한편, par(mfcol = c(4, 2)) 은 프레임을 4행 2열로 분할하되, 플롯은 열 우선 순서로 표시가 되는 것입니다. 다음의 예에서 플롯이 그려지는 순서를 잘 살펴보기 바랍니다.

library(MASS)

# par의 기본 설정 값을 저장합니다.
op <- par(no.readonly = TRUE) 

##-- par(mfcol = ) : 열 우선의 복수 플롯의 수
par(mfcol = c(4, 2),                 # 프레임을 4행 2열로 분할합니다.
    mar = c(4, 3, 3, 1),             # 내부 마진을 설정합니다.
    oma = c(0.5, 0.5, 2, 0.5))       # 외부 마진을 설정합니다.
 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 1") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 2") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 3")
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 4")
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 5") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 6") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 7") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 8") 
 
mtext("par(mfcol = c(4, 2)", outer = TRUE, cex = 2, col = "blue")

# par를 초기 설정값으로 환원합니다.
par(op)

21.4.4 영역 분할/결합 방법 2 : layout()

layout() 함수를 사용하면 행렬 형태로 분할하려는 그래프 영역의 순서(sequence)와 열의 폭과 행의 높이(widths of column, heights of row), 영역 나누기/합치기(divide/combine)를 자유롭게 조절할 수 있습니다.

layout() 함수는 par(mfrow = )par(mfcol = ) 함수와는 병행해서 사용할 수 없으므로 그래프 분석을 시작하기 전에 무슨 함수를 사용할 것인지 결정을 하고 하나를 선택해야만 합니다.

layout.show(n)은 현재의 레이 아웃에 대한 외곽선을 n 만큼의 그래프 갯수만큼 볼 수 있게 해주는 함수입니다.

아래에 layout()layout.show(n) 함수 예를 하나 들어보겠습니다. matrix() 인수 안의 숫자가 그래프가 그려지는 순서입니다. byrow=TRUE 로 설정했으므로 행 우선 순서로 4개의 그래프를 그릴 수 있는 영역에 플롯이 채워지게 됩니다. byrow= FALSE 로 지정하면 열 우선 순서로 그래프가 생성됩니다.

library(MASS)
##----------------------------------- 
## layout 
##----------------------------------- 
# par의 기본 설정 값을 저장합니다.
op <- par(no.readonly = TRUE) 
  
# 프레임을 2행 2열로 분할합니다.
# 행 우선 순서로 1, 2, 3, 4가 왼쪽으로 오른쪽 하단으로 할당됩니다.
layout(matrix(c(1, 2, 3, 4), 2, 2, byrow = TRUE))

plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 1") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 2") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 3")
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 4")

# show the current layout 
layout.show(4)

layout() 함수를 활용하면 그래프 영역을 합칠 수도 있습니다. 이러한 기능은 par(mfrow = )par(mfcol = ) 와 비교해서 매우 유용한 기능 중의 하나입니다. 2행 2열로 나눈 영역에서 1행 1열에만 그래프 영역 1개를 남겨놓고, 2행의 1열과 2행의 2열을합쳐보겠습니다.

숫자 ’0’은 비어있는 그래프 영역이 되며, 동일한 숫자를 행렬(matrix) 안에 나란히 입력하면 그 영역을 합쳐지게 됩니다.

아래 예에서는 1행2열에 ‘0’이 입력되었으므로 비어 있고, 2행1열과 2행 2열에는’2’가 입력되어 있으므로, 2행은 1개의 그래프 영역으로 표시가 되게 됩니다.

library(MASS)
## 2행 2열 영역으로 분할합니다.
## 1행 1열의 요소로 그림 1을 할당합니다.
## 그림 2은 2행 전체에 할당합니다.
layout(matrix(c(1, 0, 2, 2), 2, 2, byrow = TRUE)) 

plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 1") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 2") 

## show the current layout 
layout.show(2)

이해를 돕기위해서 이번에는 1행 1열과 1행 2열을 하나로 합치고, 2행 1열은 비워놓고 2행2열만 남겨놓는 layout을 만들어보는 예제를 아래에 들어보겠습니다.

## 2행 2열 영역으로 분할합니다.
## 그림 1을 1행 전체에 할당합니다.
## 그림 2은 2행의 2열에 할당합니다.
layout(matrix(c(1, 1, 0, 2), 2, 2, byrow = TRUE)) 

plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 1") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 2") 

## show the current layout 
layout.show(2)

이번에는 10cm x 10cm 정사각형 모양의 그래프 영역을 생성해 보겠습니다. widths = lcm() 으로, 높이heights = lcm() 으로 설정을 해주면 됩니다.

## 10 cm x 10 cm 넓이의 그래프를 작성합니다.
layout.1 <- layout(matrix(1),                                   # 요소가 1개인 행렬입니다.
                   widths = lcm(10),                            # 폭이 10cm
                   heights = lcm(10))                           # 높이가 10cm

plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 1") 

layout.show(layout.1)

이번에는 그래프 생성 순서(sequence)의 위, 아래를 바꾸어 보고, 그래프의 넓이(widths)와 높이(heights)를 서로 다르게 하는 그래프 영역을 만들어보겠습니다.

가운데에 산점도를 그려놓고 상단과 우측에 작은 크기의 히스토그램이나 박스플롯을 병행해서 그릴 때 유용하게 사용할 수 있습니다.

참고로, respect = TRUE 는 가로 넓이와 세로 높이의 비율을 고려해서 그래프 영역을 설정하라는 옵션입니다.

# 다음의 행렬에 있는 요소가 표시되는 그림의 번호입니다.
l <- matrix(c(2, 0, 1, 3), 2, 2,byrow = TRUE); l
##      [,1] [,2]
## [1,]    2    0
## [2,]    1    3
layout.2 <- layout(matrix(c(2, 0, 1, 3), 2, 2,byrow = TRUE),    # 그림의 위치를 지정합니다.     
                   widths = lcm(c(6, 4)),         # 두 열의 넓이가 각각 6Cm와 4Cm로 설정됩니다.
                   heights = lcm(c(4, 6)),        # 두 행의 높이가 각각 4Cm와 6Cm로 설정됩니다.              
                   respect = TRUE)                # 가로의 넓이와 세로의 높이의 비율을 고려합니다.

plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 1") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 2") 
plot(MPG.highway ~ Weight, Cars93, type="p", main = "plot 3")

layout.show(layout.2) 

# Reset par to the default values at startup 
par(op)