정보의 구조화

단원 01 자료와 그래프 · 중등 정보교과 연계 · 도입

개념

같은 내용이라도 어떻게 구조화하느냐에 따라 전달력이 크게 달라집니다. 잘 정리된 정보는 의미가 한눈에 들어오지만, 뒤섞인 정보는 뜻이 잘못 전달되기도 합니다. 중등 「정보」 교과서는 정보를 정리하는 네 가지 대표 형태를 소개합니다.

  • 순차적 구조 — 내용을 순서대로 나열합니다. 쉽고 빠르지만 양이 많아지면 관리가 어렵습니다.
  • 표(테이블) 구조 — 행과 열로 나눕니다. 시간표·출석부처럼 항목별 비교에 강합니다.
  • 계층형 구조 — 수준별로 묶습니다. 조직도·목차·폴더처럼 큰 것에서 작은 것으로 내려갑니다.
  • 다이어그램 구조 — 기호·선·점으로 관계와 크기를 보여 줍니다. 그래프가 여기에 속합니다.

“우리나라 시도별 인구수를 어떻게 하면 효과적으로 전달할까?” — 교과서가 던지는 이 질문이 바로 통계 그래프의 출발점입니다. 정답은 하나가 아니라 활용 목적에 따라 달라집니다.

핵심은 어느 하나가 항상 옳은 것이 아니라, 정보의 활용 목적에 맞는 형태를 고르는 것입니다. 개별 값을 정확히 찾아야 하면 표가, 소속 관계를 보여야 하면 계층이, 크기를 한눈에 비교하려면 다이어그램이 유리합니다. 아래 앱에서 같은 인구 데이터를 네 형태로 바꿔 보며 차이를 느껴 보세요.

만지며 배우기

#| '!! shinylive warning !!': |
#|   shinylive does not work in self-contained HTML documents.
#|   Please set `embed-resources: false` in your metadata.
#| standalone: true
#| viewerHeight: 640

from shiny import App, render, ui

ACCENT = "#2563eb"

# 시도를 권역으로 묶은 계층 구조 (인구는 백만 명 단위, 교과서 표 기준 반올림)
REGIONS = {
    "수도권": [("서울", 10.0), ("인천", 2.9), ("경기", 12.5)],
    "충청권": [("대전", 1.5), ("세종", 0.2), ("충북", 1.6), ("충남", 2.1)],
    "호남권": [("광주", 1.5), ("전북", 1.9), ("전남", 1.9)],
    "영남권": [("부산", 3.5), ("대구", 2.5), ("울산", 1.2),
             ("경북", 2.7), ("경남", 3.4)],
    "강원권": [("강원", 1.5)],
    "제주권": [("제주", 0.6)],
}
FLAT = [(name, pop) for cities in REGIONS.values() for (name, pop) in cities]

app_ui = ui.page_sidebar(
    ui.sidebar(
        ui.input_radio_buttons(
            "form", "구조화 형태",
            {"seq": "순차적", "table": "표(테이블)",
             "tree": "계층형", "diagram": "다이어그램"},
            selected="table",
        ),
        width=250,
    ),
    ui.card(
        ui.card_header("같은 데이터, 네 가지 구조 — 목적에 맞는 형태는?"),
        ui.output_ui("view"),
    ),
    ui.card(ui.output_ui("note")),
    fillable=True,
)

def server(input, output, session):
    @render.ui
    def view():
        form = input.form()

        if form == "seq":
            items = " → ".join(f"{n} {p}" for n, p in FLAT)
            return ui.HTML(
                '<p style="line-height:2; font-size:0.95em;">' + items + "</p>"
            )

        if form == "table":
            td = ('style="border:1px solid #d1d5db; padding:3px 12px;'
                  ' text-align:center;"')
            rows = "".join(
                f"<tr><td {td}>{n}</td><td {td}>{p:.1f}</td></tr>"
                for n, p in FLAT
            )
            return ui.HTML(
                '<table style="border-collapse:collapse; margin:0 auto;'
                ' font-size:0.9em;">'
                f"<tr><th {td}>시도</th><th {td}>인구(백만)</th></tr>"
                f"{rows}</table>"
            )

        if form == "tree":
            blocks = ""
            for region, cities in REGIONS.items():
                total = sum(p for _, p in cities)
                leaves = "".join(
                    f'<li style="margin-left:1.4em;">{n} — {p:.1f}백만</li>'
                    for n, p in cities
                )
                blocks += (
                    f'<li style="font-weight:600; margin-top:0.4em;">'
                    f"{region} ({total:.1f}백만)</li>{leaves}"
                )
            return ui.HTML(
                f'<ul style="list-style:none; padding-left:0.5em;'
                f' line-height:1.7; font-size:0.92em;">{blocks}</ul>'
            )

        # diagram — 권역별 합계를 HTML 막대로
        totals = {r: sum(p for _, p in c) for r, c in REGIONS.items()}
        mx = max(totals.values())
        bars = ""
        for region, t in sorted(totals.items(), key=lambda x: -x[1]):
            w = t / mx * 100
            bars += (
                '<div style="display:flex; align-items:center; margin:6px 0;">'
                f'<div style="width:70px; text-align:right; padding-right:10px;'
                f' font-size:0.88em;">{region}</div>'
                f'<div style="height:20px; width:{w:.1f}%; background:{ACCENT};'
                f' border-radius:3px;"></div>'
                f'<div style="padding-left:8px; font-size:0.85em;'
                f' color:#6b7280;">{t:.1f}</div></div>'
            )
        return ui.HTML(f'<div style="padding:0.5em 0;">{bars}</div>')

    @render.ui
    def note():
        msg = {
            "seq": "순차적 구조는 빠르게 나열하지만, 17개가 한 줄로 늘어서면 "
                   "어디에 무엇이 있는지 찾기 어렵습니다.",
            "table": "표는 개별 시도의 정확한 값을 찾기에 가장 좋습니다. "
                     "대신 전체 크기를 한눈에 비교하기는 어렵습니다.",
            "tree": "계층형은 '어느 권역에 속하는가'라는 소속 관계를 드러냅니다. "
                    "권역별 합계까지 함께 보여 줄 수 있습니다.",
            "diagram": "다이어그램(막대)은 크기 비교가 즉각적입니다. "
                       "수도권이 다른 권역을 압도한다는 사실이 바로 읽힙니다. "
                       "통계 그래프가 여기에 해당합니다.",
        }[input.form()]
        return ui.HTML(f'<p class="hs-readline">{msg}</p>')

app = App(app_ui, server)

계층형 구조는 딕셔너리로, 권역별 합계는 반복문으로 간단히 표현됩니다.

regions = {
    "수도권": {"서울": 10.0, "인천": 2.9, "경기": 12.5},
    "영남권": {"부산": 3.5, "대구": 2.5, "울산": 1.2, "경북": 2.7, "경남": 3.4},
}

for region, cities in regions.items():
    total = sum(cities.values())         # 권역 = 상위 계층
    print(f"{region}: {total:.1f}백만")   # 시도 = 하위 계층

스스로 확인

개별 값을 정확히 찾는 데는 표(테이블) 구조가 가장 적합합니다. 다이어그램은 크기를 눈대중으로 비교하기엔 좋지만 정확한 숫자를 읽기는 어렵고, 순차 구조는 항목이 많으면 원하는 값을 찾기 번거롭습니다.

독자에게 필요한 것은 정확한 자릿수가 아니라 “어디가 많고 어디가 적은가” 라는 크기 관계이기 때문입니다. 다이어그램은 이 비교를 순식간에 전달합니다. 활용 목적이 ’정확한 조회’가 아니라 ’한눈에 비교’일 때 다이어그램이 가장 효과적입니다.