HOWTO · R
R ggplot2에서 축 눈금 레이블 변경하기
ggplot2의 불연속형·연속형 축 눈금 레이블을 바꾸고 형식을 지정하며, 긴 레이블의 겹침을 해결하는 방법을 설명합니다.
요인이나 문자형 눈금의 이름은 scale_x_discrete(labels = ...)로 바꾸고, 숫자 눈금의 위치와 표시는 scale_x_continuous(breaks = ..., labels = ...)로 지정합니다. 회전 같은 모양은 theme(axis.text.x = element_text(...))에서 조정합니다. 축 제목을 바꾸는 labs(x = ...)는 눈금 레이블과 다른 요소입니다. 세로축에는 각 함수의 x를 y로 바꾸어 같은 원리를 적용합니다.
예제를 실행하려면 R과 ggplot2가 필요하며, 연속형 예제의 서식 지정에는 scales도 사용합니다. 검증 환경은 R 4.1.2, ggplot2 3.3.5, scales 1.1.1입니다. 여기서 사용한 척도 인수는 현재 ggplot2에도 있지만 설치 버전에 따라 테마의 세부 표현이 달라질 수 있습니다.
| 작업 | ggplot2 설정 |
|---|---|
| 축 제목 변경 | labs(x = "Title") 또는 labs(y = "Title") |
| 요인·문자형 눈금 이름 변경 | scale_x_discrete(labels = ...) |
| 숫자 눈금 위치와 텍스트 설정 | scale_x_continuous(breaks = ..., labels = ...) |
| 표시된 눈금 텍스트 회전·스타일 지정 | theme(axis.text.x = element_text(...)) |
Date 축 서식 지정 |
scale_x_date(breaks = ..., labels = ...) |
기준 ggplot2 그래프 만들기
각 변경 효과를 쉽게 비교하도록 작은 데이터 프레임 하나를 계속 사용합니다. plan 열은 요인이므로 x축은 불연속형 척도이고, 숫자형 orders 열은 연속형 y축을 사용합니다.
library(ggplot2)
plan_sales <- data.frame(
plan = factor(
c("starter", "standard", "premium", "enterprise"),
levels = c("starter", "standard", "premium", "enterprise")
),
orders = c(180, 250, 210, 140)
)
base_plot <- ggplot(plan_sales, aes(x = plan, y = orders)) +
geom_col(fill = "#2c7fb8", width = 0.7) +
labs(x = "Plan", y = "Orders") +
theme_minimal(base_size = 16)
base_plot
ggsave(
"ggplot-default-axis-tick-labels.png",
plot = base_plot, width = 7.4, height = 4.82, dpi = 100, bg = "white"
)
x축에는 저장된 네 요인 값이, y축에는 자동으로 선택된 숫자 눈금이 표시됩니다. labs(x = "Plan")은 x축 제목인 “Plan”을 설정할 뿐 starter나 standard 같은 눈금 텍스트를 바꾸지 않습니다.
척도를 고르기 전에 그래프 모양으로 추측하지 말고 매핑한 변수를 확인합니다. str(plan_sales$plan)은 요인, str(plan_sales$orders)는 숫자 벡터라고 알려 줍니다. "1", "2"처럼 숫자로 보이는 코드를 가진 요인도 불연속형이며, 고유 값이 몇 개뿐인 숫자 열도 연속형입니다. 자료형 변환은 바뀐 형식이 값의 의미와 맞을 때만 해야 합니다.
불연속형 축 눈금 레이블의 이름과 순서 변경하기
불연속형 척도에서는 breaks와 labels를 짝지어 지정합니다. breaks는 눈금을 표시할 원본 데이터 값을 고르고, labels는 그 위치에 출력할 텍스트를 제공합니다. 둘을 명시하면 나중에 척도 순서가 달라져도 레이블이 잘못 연결되는 일을 막을 수 있습니다.
다음 예제는 데이터 복사본의 요인 수준을 바꾸고 같은 순서를 breaks에 전달합니다. 이름이 지정된 레이블 벡터를 사용하므로 실행 전에도 대응 관계가 명확합니다.
plan_order <- c("premium", "standard", "starter", "enterprise")
plan_names <- c(
premium = "Premium",
standard = "Standard",
starter = "Starter",
enterprise = "Enterprise"
)
ordered_sales <- plan_sales
ordered_sales$plan <- factor(ordered_sales$plan, levels = plan_order)
discrete_plot <- ggplot(ordered_sales, aes(x = plan, y = orders)) +
geom_col(fill = "#2c7fb8", width = 0.7) +
scale_x_discrete(
breaks = plan_order,
labels = plan_names[plan_order]
) +
labs(x = "Plan", y = "Orders") +
theme_minimal(base_size = 16)
discrete_plot
ggsave(
"ggplot-discrete-axis-tick-labels.png",
plot = discrete_plot, width = 7.4, height = 4.82, dpi = 100, bg = "white"
)
표시 순서는 Premium, Standard, Starter, Enterprise입니다. 소문자로 저장된 데이터 값은 그대로이고 표현만 바뀝니다. 모든 눈금에 한 규칙을 적용할 때는 scale_x_discrete(labels = abbreviate)처럼 레이블 함수를 쓸 수 있습니다. 이 코드는 모든 눈금값을 base R의 abbreviate()에 전달합니다. 사용자 정의 function(x)는 입력과 길이가 같은 문자 벡터를 반환해야 합니다.
현재 순서를 유지하며 이름만 바꾼다면 breaks를 생략하고 c(starter = "Starter", standard = "Standard", premium = "Premium", enterprise = "Enterprise")처럼 표시할 값을 모두 포함한 이름이 지정된 벡터를 전달할 수 있습니다. 표시 집합과 순서가 모두 요구 사항이면 위의 명시적 짝이 더 안전합니다. 데이터를 필터링한 뒤 x축을 왼쪽부터 읽어 여기에 적은 예상 순서와 맞는지 확인하십시오.
breaks와 limits는 서로 바꿔 쓸 수 없습니다. 불연속형 척도의 breaks는 허용하는 범주를 바꾸지 않고 표시할 눈금만 고릅니다. limits는 허용 값과 순서를 정하며, 밖의 값을 결측값으로 바꾸므로 geom_col() 같은 레이어가 경고와 함께 해당 행을 제거할 수 있습니다. 순서가 데이터 의미라면 요인 수준을 바꾸고, limits는 값을 의도적으로 제외할 때만 사용합니다.
연속형 축 눈금 위치와 형식 지정하기
숫자 축에는 연속형 척도를 씁니다. 정확한 위치는 breaks로, 대응 텍스트나 서식 지정 함수는 labels로 전달합니다. 값이 바뀔 수 있다면 ggplot2가 최종 눈금 위치를 인수로 호출하는 함수가 더 안전합니다.
다음 산점도는 마력 눈금을 100, 200, 300에 놓고 scales::label_number()로 단위를 덧붙입니다. 그리기 전에 서식 함수를 직접 호출하여 실제 레이블 텍스트도 확인합니다.
hp_breaks <- c(100, 200, 300)
hp_formatter <- scales::label_number(suffix = " hp", accuracy = 1)
hp_formatter(hp_breaks)
continuous_plot <- ggplot(mtcars, aes(x = hp, y = mpg)) +
geom_point(size = 3, color = "#d95f0e") +
scale_x_continuous(
breaks = hp_breaks,
labels = hp_formatter
) +
labs(x = "Engine power", y = "Fuel economy (mpg)") +
theme_minimal(base_size = 16)
continuous_plot
ggsave(
"ggplot-continuous-axis-tick-labels.png",
plot = continuous_plot, width = 7.4, height = 4.82, dpi = 100, bg = "white"
)
[1] "100 hp" "200 hp" "300 hp"
x축에는 이 세 위치와 레이블만 보여야 합니다. 숫자 y축에는 같은 방식으로 scale_y_continuous()를 사용합니다. scales의 다른 함수는 천 단위 구분, 백분율, 통화 등을 표시할 수 있으며 데이터는 계속 숫자형입니다.
이 마력 값처럼 위치 자체에 의미가 있으면 breaks를 정확히 지정합니다. 형식만 중요하다면 breaks를 생략하고 ggplot2가 데이터 범위에서 위치를 고르게 합니다. 단위를 붙이려고 숫자 열을 문자열로 미리 변환하면 척도 유형이 바뀌어 숫자 간격 대신 사전순으로 정렬될 수 있습니다. 서식 함수는 계산과 점의 위치는 유지하고 보이는 텍스트만 바꿉니다.
날짜는 별도의 척도 유형입니다. 매핑한 열이 Date를 상속하면 숫자나 불연속형 척도로 강제하지 말고 scale_x_date() 또는 y축 대응 함수를 씁니다. 날짜용 눈금 위치 및 서식을 사용하지만 breaks와 labels의 원리는 같습니다.
겹치는 눈금 레이블 회전하기
레이블 내용 변경과 텍스트 스타일 변경은 다른 문제입니다. 내용이 맞지만 겹친다면 척도는 유지하고 테마의 axis.text.x를 조정합니다. angle = 35는 회전하며 hjust = 1은 오른쪽 끝을 눈금에 맞춥니다. 큰 기본 글꼴은 좁은 그래프에서도 읽기 쉽도록 합니다.
channel_sales <- data.frame(
channel = c(
"North America Online",
"Europe Retail Stores",
"Asia Pacific Partners",
"Latin America Direct"
),
orders = c(260, 220, 195, 150)
)
rotated_plot <- ggplot(channel_sales, aes(x = channel, y = orders)) +
geom_col(fill = "#31a354", width = 0.65) +
labs(x = "Sales channel", y = "Orders") +
theme_minimal(base_size = 18) +
theme(
axis.text.x = element_text(angle = 35, hjust = 1, vjust = 1)
)
rotated_plot
ggsave(
"ggplot-rotated-axis-tick-labels.png",
plot = rotated_plot, width = 7.4, height = 4.82, dpi = 100, bg = "white"
)
회전해도 모든 범주 이름은 남습니다. 여전히 겹치면 각도를 더 키우기보다 문구를 줄이거나 그래프를 넓히는 편이 더 잘 전달될 수 있습니다. 검증된 ggplot2 3.3.5에서는 scale_x_discrete(guide = guide_axis(n.dodge = 2))로 불연속형 레이블을 두 줄에 엇갈리게 놓을 수 있으며 이 함수는 현재 API에도 있습니다. 가로 텍스트를 유지하지만 세로 공간을 더 씁니다. 다른 선택지는 base R 또는 ggplot2에서 축 레이블 회전하기를 참고하십시오.
레이블, 축 눈금 표시 또는 눈금 위치를 의도적으로 숨기기
이 설정들을 같은 것으로 보지 말고 제거할 요소에 맞춰 선택합니다.
control_plot <- base_plot +
theme_classic(base_size = 16)
labels_hidden <- control_plot +
theme(axis.text.x = element_blank())
ticks_hidden <- control_plot +
theme(axis.ticks.x = element_blank())
breaks_hidden <- control_plot +
scale_x_discrete(breaks = NULL)
control_plot의 theme_classic()은 축에 짧은 눈금 표시를 그리므로 각 변경과 비교할 수 있습니다. labels_hidden은 x축 텍스트만 없앱니다. ticks_hidden은 축 눈금 표시만 없애고 범주 이름은 남깁니다. breaks_hidden은 주요 x축 눈금 위치를 만들지 않아 그 위치의 레이블과 축 눈금 표시가 함께 사라집니다. 어느 표현도 plan_sales의 행을 필터링하지 않습니다.
척도에서 labels = NULL을 지정하면 눈금 위치를 유지하면서 레이블을 숨깁니다. 척도 정의상 레이블이 없어야 할 때 사용하고, 특정 그래프 테마에서만 텍스트를 그리지 않을 때는 element_blank()를 사용합니다. 범주가 중요하다면 숨긴 텍스트 대신 직접 주석이나 다른 키를 제공해야 합니다.
이 세 객체는 선택 가능한 코드와 설명으로 비교하는 편이 쉬워 이미지로 저장하지 않았습니다. R 콘솔에서 ticks_hidden을 출력해 control_plot과 비교하십시오. 세 결과 모두 막대와 높이는 그대로이며 축 안내 요소만 달라집니다. 도형이 달라지거나 행 제거 경고가 나오면 여기의 테마가 아니라 다른 limits 호출을 확인합니다.
잘못되거나 누락된 눈금 레이블 문제 해결하기
연속형 값을 불연속형 척도에 제공했다는 오류나 그 반대 오류가 나오면 str()로 열을 확인합니다. 요인·문자 열에는 불연속형, 숫자 열에는 연속형, Date와 날짜·시간 객체에는 해당 날짜 척도를 씁니다. 오류만 없애려고 변환하지 말고 값의 실제 의미와 맞을 때만 자료형을 바꿉니다.
labels에 문자 벡터를 쓸 때는 명시적 breaks와 짝짓고 길이를 같게 유지합니다. 그렇지 않으면 필터링, 재정렬, 범주 추가 뒤에 레이블이 밀릴 수 있습니다. plan_names 같은 이름이 지정된 매핑은 저장 값과 표시 이름의 관계를 보여 줍니다. 모든 눈금값에 한 변환을 적용할 때는 함수가 길이 문제를 피합니다.
막대가 사라지거나 행 제거 경고가 나타나면 labels보다 limits를 의심합니다. 데이터 값이 척도 제한에서 빠졌는지 확인하고, 보이는 눈금 수만 줄이려면 breaks를 씁니다. 의도적인 확대나 범위 제어는 눈금 위치와 혼동하지 않고 ggplot2 축 제한 설정하기를 참고하십시오.
마지막으로 바꾸려는 텍스트가 축 제목인지 확인합니다. labs(x = "Plan")과 x 척도의 name 인수는 제목을 설정하고 labels 인수는 눈금 텍스트를 제어합니다. 역할을 구분하면 제목만 바뀌고 범주나 숫자 레이블은 그대로인 혼란을 막을 수 있습니다.
대부분의 그래프에서는 매핑한 자료형에 맞는 척도를 고르고 정확한 텍스트에는 breaks와 labels를 짝지으며 모양만 theme()에 맡깁니다. 이렇게 하면 원본 관측값을 유지하면서 축을 예측 가능하게 바꿀 수 있습니다.