본문 바로가기

Org Mode 테이블 스프레드시트

기술적인 이야기/이맥스 2020. 1. 31.
반응형

Org Mode 문서의 테이블은 다양한 기능을 제공합니다. 그중 하나가 테이블 셀을 이용해 계산을 하는 것입니다. 마치 엑셀이나 Numbers, 구글 독스에서 제공하는 스프레드시트(Spreadsheet)와 비슷합니다. 이 기능에 대해 간략히 정리해 보는 글입니다.

참고로 이 글에서 언급하는 단축키는 Doom Emacs 기준입니다.

테이블

일단 아래와 같은 테이블을 만들었다고 가정해봅시다.

| Kind  | Price | Ideal | Earning |
|-------+-------+-------+---------|
| Book  |   100 |    99 |         |
| Apple |   256 |    30 |         |
| Coke  |     4 |     9 |         |
|-------+-------+-------+---------|
|       |       |       |         |

영어 의미에 집착하지는 맙시다. 저도 어차피 콩글리쉬 유저입니다. 하여간 이 테이블은 Org Mode에서 제공하는 테이블 그리기 기능을 이용하면 손쉽게 만들 수 있습니다.

셀 정보 확인하기

스프레드시트에서는 행과 열에 고유번호가 붙어 있습니다. 이 고유번호는 각 셀의 위치를 알 수 있게 하기 위함이지요. Org Mode의 테이블에도 비슷한 고유 번호 시스템이 있습니다.

우선 커서를 아래 [] 위치에 놨다고 가정합시다.

| Kind  | Price | Ideal | Earning |
|-------+-------+-------+---------|
| Book  |   100 |    99 |      [] |
| Apple |   256 |    30 |         |
| Coke  |     4 |     9 |         |
|-------+-------+-------+---------|
|       |       |       |         |

커서 위치의 셀 주소(?)를 파악하기 위해 C-c ? 혹은 SPC m b h 키를 눌러봅시다. 그러면 하단 미니 버퍼에 커서가 있는 위치의 주소를 알 수 있습니다. 위 가정의 경우 아래와 같은 메시지가 나타났습니다.

line @2, col $4, ref @2$4 or D2

여기서 @2$4라는 값이 커서가 위치한 셀의 위치를 한 번에 나타내는 셀 주소입니다. 이 표현 방식을 잘 살펴봐 둡시다. 나중에 계산을 할 때 이 주소를 사용하기 때문입니다.

필요한 내용은 이미 알았지만, 이 외의 다른 정보도 확인해봅시다. C-c } 키를 누르면 테이블 헤더에 주소 정보가 토글 됩니다.

   1| Kind  | Price | Ideal | Earning |
I*1 |$1-----+$2-----+$3-----+$4-------|
   2| Book  |   100 |    99 |      [] |
   3| Apple |   256 |    30 |         |
   4| Coke  |     4 |     9 |         |
I*2 |$1-----+$2-----+$3-----+$4-------|
   5|       |       |       |         |

이 정보를 통해서 $1부터 $4까지 표시되는 것이 칼럼(행, Column) 번호임을 유추할 수 있습니다. 그렇다면 남은 골뱅이는 로우(열, Row) 번호겠군요. 좌측의 숫자만 표시된 영역이 바로 로우 번호입니다. I*1처럼 표시된 것은 구분자의 위치로 볼 수 있겠네요.

앞서 토글 된다고 이야기했다시피 이 정보는 같은 단축키를 한번 더 누르면 토글 돼서 없어집니다.

Lisp 함수 실행시켜보기

이제 한 가지 특수한 짓(?)을 해봅시다. 2번 로우의 2, 3번 칼럼의 값의 차이가 얼마인지를 구해서 그 오른쪽의 Earning 칼럼에 붙여봅시다. 커서가 위치한 곳인 [] 위치에서 아래와 같은 내용을 입력해 봅시다.

:='(- @2$3 $2$2);N

위 텍스트를 입력하고 끝에서 TAB 키를 눌러주면 뭔가 변화가 생깁니다.

| Kind  | Price | Ideal | Earning            |
|-------+-------+-------+--------------------|
| Book  |   100 |    99 | -1                 |
| Apple |   256 |    30 |                    |
| Coke  |     4 |     9 |                    |
|-------+-------+-------+--------------------|
|       |       |       |                    |
#+TBLFM: @2$4='(- @2$3 @2$2);N

-1이라는 값이 찍힌 것을 볼 수 있습니다. 3번 칼럼의 값($3)에서 2번 컬럼의 값($2)을 뺀 -1이라는 값이 찍힌 것입니다.

자 그럼 아까 입력했던 내용의 의미를 잠깐 이해해봅시다.

  • :=은 이 셀에는 이후에 나오는 내용으로 치환시킨다는 의미입니다.
  • '는 Lisp의 quote 함수입니다. 잘 모르겠다면 현재 상황에서는 꼭 써야 한다고 생각하면 될 것 같습니다.
  • (- @2$3 @2$2)는 Lisp 코드로 2열 3행의 값에서 2열 2행의 값을 뺀다는 의미입니다.
  • ;N은 Lisp 코드의 끝을 의미합니다.

이것 말고도 표의 하단에 아래와 같은 특수한 커맨드가 추가되어 있는 것이 보일 것입니다.

#+TBLFM: @2$4='(- @2$3 @2$2);N

#+ 로 시작하는 표기는 Org Mode 문서의 특수 커맨드라는 의미로 이해가 됩니다. 아마도 방금 입력했던 식을 다르게 표시한 것으로 유추가 됩니다.

그렇다면 이 #+ 부분을 약간 고치면 몽땅 고칠 수 있을까요? TBLFM의 내용을 아래처럼 고쳐봅시다.

#+TBLFM: $4='(- $3 $2);N

수정한 뒤에는 C-c C-c 키를 눌러야 반영이 됩니다. 그러면 아래처럼 표시될 것입니다.

| Kind  | Price | Ideal | Earning |
|-------+-------+-------+---------|
| Book  |   100 |    99 |      -1 |
| Apple |   256 |    30 |    -226 |
| Coke  |     4 |     9 |       5 |
|-------+-------+-------+---------|
|       |       |       |       0 |
#+TBLFM: $4='(- $3 $2);N

4행의 값은 3행 빼기 2행의 값이다 라는 것을 정의해 버렸습니다. 이제 자동으로 입력된 값 외의 다른 값을 수정하면 제일 오른쪽 행의 값이 자동으로 바뀝니다. 그야말로 엑셀 같은 스프레드시트가 되었네요. 불행히도 마지막 열 까지 데이터가 입력되어 버린 것은 좀 안타깝지만요.

시작부터 Lisp 코드를 사용해버린 것은 그냥 리습 코드도 쓸 수 있다는 예를 보여주고 싶었을 뿐입니다. 이제 이런 변태같은(?) 코드는 사용하지 않을게요.😉

 

사칙연산 사용해보기

이제 Lisp 코드 말고 calc를 통해 제공되는 계산기 기능을 써 봅시다. 앞의 내용과 비슷한 기능을 시험해 보기 위해 다시 테이블을 원래대로 리셋시켰습니다.

| Kind  | Price | Ideal | Earning |
|-------+-------+-------+---------|
| Book  |   100 |    99 |      [] |
| Apple |   256 |    30 |         |
| Coke  |     4 |     9 |         |
|-------+-------+-------+---------|
|       |       |       |         |

커서 위치도 여전히 []로 표시한 부분인 Earning 칼럼의 첫 로우에 있습니다. 이 위치에서 이제 아래와 같은 내용을 입력해봅시다.

=$3-$2

이번엔 뭔가 아까랑 다르네요. := 대신 그냥 =으로 시작합니다. 내용도 Lisp 코드에 비하면 좀 더 읽기 쉬워 보입니다.

어쨌든 입력을 하고 TAB 키를 누르는 순간 비슷하게 아래와 같이 표시됩니다.

| Kind  | Price | Ideal | Earning |
|-------+-------+-------+---------|
| Book  |   100 |    99 |      -1 |
| Apple |   256 |    30 |         |
| Coke  |     4 |     9 |         |
|-------+-------+-------+---------|
|       |       |       |         |
#+TBLFM: $4=$3-$2

여기까진 특별해 보이는 것이 없어 보이네요.

이제 살짝 마법을 써 봅시다. 하단의 #+TBLFM 쪽으로 커서를 가져한 후 C-c C-c 키를 눌러봅시다.

| Kind  | Price | Ideal | Earning |
|-------+-------+-------+---------|
| Book  |   100 |    99 |      -1 |
| Apple |   256 |    30 |    -226 |
| Coke  |     4 |     9 |       5 |
|-------+-------+-------+---------|
|       |       |       |       0 |
#+TBLFM: $4=$3-$2

짜잔~ Earning 칼럼에 데이터가 자동으로 계산되어 들어갔습니다. 왠지 :(콜론) 오퍼레이터 존재의 의미가 이해가 갈 것 같습니다. := 오퍼레이터는 현재 셀에만 함수를 적용한다는 의미이고, = 오퍼레이터는 이 행이나 열 전체에 해당 함수를 적용한다는 의미일 것 같네요.

비록 가장 아래쪽에 이상한 데이터가 하나 들어가긴 했지만요.

합계 구하기

이제 Price와 Ideal 수치 합계를 한번 계산해 봅시다. 제일 아래의 빈 로우에 값을 채워 넣을 예정입니다. 여전히 커서는 []로 표시한 위치에 있다고 가정합시다.

| Kind  | Price | Ideal | Earning |
|-------+-------+-------+---------|
| Book  |   100 |    99 |      -1 |
| Apple |   256 |    30 |    -226 |
| Coke  |     4 |     9 |       5 |
|-------+-------+-------+---------|
|       |    [] |       |       0 |
#+TBLFM: $4=$3-$2

이번엔 조금 다른 방법을 써서 편집해 봅시다. SPC m b e 키를 누르면 하단에 별도의 버퍼가 열리면서 여기에 해당 셀에 입력할 값을 별도로 입력할 수 있습니다. 이 특수 버퍼에 아래와 같은 내용을 입력해 봅시다.

:=vsum(@2$2..@4$2)

미니버퍼에 잘 표시가 되어있지만 위의 것을 입력한 후 C-c C-c 키를 눌러야만 입력한 내용이 셀에 반영됩니다. 사실 수동으로 그 위치에 입력하는 거랑 별 차이는 없으니 편한 방법을 쓰면 됩니다. 😏

이제 할 일은 입력된 내용 위에서 =TAB= 키를 눌러보는 것입니다.

| Kind  | Price | Ideal | Earning |
|-------+-------+-------+---------|
| Book  |   100 |    99 |      -1 |
| Apple |   256 |    30 |    -226 |
| Coke  |     4 |     9 |       5 |
|-------+-------+-------+---------|
|       |   360 |       |       0 |
#+TBLFM: $4=$3-$2::@5$2=vsum(@2$2..@4$2)

짜잔~ 이젠 아래에 Price 합계가 표시되었습니다. 그리고 제일 하단에 TBLFM 항목에도 방금 입력한 것과 비슷한 명령이 추가되어 있습니다. ::는 구분자인가 보네요.

입력했던 내용 자체는 앞서 살펴본 것과 비슷합니다. 다만 vsum 함수는 지정된 범위 내의 데이터를 합하기 위한 calc 패키지의 함수입니다.

자 그렇다면 남은 빈 곳도 채우기 위해 직접 TBLFM 코드를 수동으로 수정해 봅시다.

#+TBLFM: $4=$3-$2::@5=vsum(@2..@4)

vsum 입력 인자에서 모든 행을 대상으로 하도록 수정했습니다. 물론 고친 다음에 C-c C-c 를 입지 맙시다. 이렇게 하면 짜잔~

| Kind                | Price | Ideal | Earning |
|---------------------+-------+-------+---------|
| Book                |   100 |    99 |      -1 |
| Apple               |   256 |    30 |    -226 |
| Coke                |     4 |     9 |       5 |
|---------------------+-------+-------+---------|
| Book + Apple + Coke |   360 |   138 |    -222 |
#+TBLFM: $4=$3-$2::@5=vsum(@2..@4)

뭔가 다 채워지긴 했는데 이상하군요! 아하하🤦

 

계산 영역 제한하기

위 결과에서 좌측 하단의 이상한 것(?)을 지워봅시다. 일단 방금 명령으로 입력되어 버린 모든 내용을 초기화하기 위해 제일 아래 로우 각 셀의 내용을 수동으로 다 지웠습니다.

그리고 TBLFM의 가장 마지막 항목을 아래처럼 고쳐봤습니다.

#+TBLFM: $4=$3-$2::@5$2..@5$4=vsum(@2..@4)

그리고 TBLFM 위에서 C-c C-c 를 눌러보면 아래처럼 나옵니다.

| Kind  | Price | Ideal | Earning |
|-------+-------+-------+---------|
| Book  |   100 |    99 |      -1 |
| Apple |   256 |    30 |    -226 |
| Coke  |     4 |     9 |       5 |
|-------+-------+-------+---------|
|       |   360 |   138 |    -222 |
#+TBLFM: $4=$3-$2::@5$2..@5$4=vsum(@2..@4)

짜잔~ 원하던 데로 이상한 'Book + Apple + Coke'라는 이상한 데이터가 사라졌습니다.

위에서 사용한 코드는 값이 들어가는 부분을 영역으로 표현했습니다. @5$2..@5$4 까지만 vsum의 결과를 적용하겠다는 의미로 사용했지요. 이런 식으로도 할 수 있다는 것을 보여주고 싶었습니다.

비록 중복으로 뭔가 바뀌는 셀이 있다는 경고 메시지가 나오기는 하지만 뭐 원하는 대로 결과가 나왔으니 다 좋은 거겠지요 뭐...😏

calc 함수 목록

아래 함수는 스프레드시트 연산에 사용할 수 있는 다양한 함수들입니다. 모든 것을 정리한 것은 아니고 일단 정보를 구한 것만 정리합니다. 더 많은 함수가 있을 수 있습니다.

  • exp(c) 지수(exponential)
  • log(c) log
  • log10(c) log10
  • sqrt(c) 루트(SQRT, Square-Root)
  • vcor(v1, v2) 상관계수(correlation)
  • vcount(v) 개수
  • vcov(v1, v2) 공분산(covariance)
  • vlen(v) 길이(length)
  • vmax(v) 최댓값(maximum)
  • vmean(v) 평균(average)
  • vmedian(v) 중간값
  • vmin(v) 최솟값(minimum)
  • vprod(v) 곱(product)
  • vsdev(v) 표준편차(standard deviation)
  • vsum(v) 합계
  • vvar(v) 분산(variance)

마무리

사실 이 기능은 정말 대단한 기능입니다. 하지만 굳이 스프레드시트를 Org Mode 문서로 만드려고 하는 사람은 아마도 별로 없겠지요? 아무래도 가독성 측면이나 편리성 면에서도 엑셀이나 Numbers를 쓰는 것이 훨씬 편할 것입니다. 다만 Org Mode로 문서를 종종 작성하거나 작성한 문서의 테이블에서 계산을 좀 더 동적으로 하기 위해서 이 기능을 사용할 수는 있어 보입니다. 그렇다면? 뭐... 개인적으론 자주 사용할 것 같지는 않습니다.

익숙해지면 편하려나요? 물론 재미는 있어 보입니다. 🙂

728x90
반응형

댓글