이 차트의 이름이 있습니까-원형 차트와 mekko plot 사이의 십자가


9

이름은 (뉴질랜드에서 공급 아래 차트의 종류에 대한 있는가 비즈니스, 혁신과 고용의 장관 누구를 위해 I 작동하지만이 플롯을 만드는 데 참여하지 않은)? 면적이 변수에 비례하는 사각형으로 구성되며 원형 차트, 모자이크 플롯 및 mekko 플롯 간의 일종의 십자가와 유사합니다. 아마도 mekko plot에 가장 가깝지만 열로 작업하지 않고 더 복잡한 퍼즐로 작업하고 있다는 합병증이 있습니다.

각 영역의 사각형 사이에 흰색 테두리가 있으므로 원본이 약간 더 좋아 보입니다.

놀랍게도, 실제로 통계 그래픽을 나쁘지 않은 것으로 생각합니다.하지만 의미있는 것에 매핑 된 색상을 더 잘 사용하면 향상 될 수 있습니다. New York Times 는 미국 2011 예산을 보여주는 강력한 대화식 버전을 사용했습니다 .

흥미로운 과제는 자동 알고리즘을 사용하여 알고리즘을 그려서 합리적으로 보이게하는 것입니다. 사각형은 허용 가능한 범위 내에서 다른 종횡비를 가질 수 있어야합니다.

여기에 이미지 설명을 입력하십시오


이 질문으로 시작된 프로젝트의 최종 결과는 여기에서 링크 된 대화식 웹 도구에서 볼 수 있습니다. mbie.govt.nz/what-we-do/business-growth-agenda/regions
Peter Ellis

답변:



12

문제는 이름이지만 그것이 얼마나 잘 작동하는지도 토론 할 수 있습니다.

대체 가로 막 대형 차트로 훨씬 더 유망한 것이 있습니다.

여기에 이미지 설명을 입력하십시오

이러한 그래프를 사용하여 수행 할 수있는 작업은 전체 패턴 파악에서 개별 사례에 대한 조사 (호크스 베이 등)에 이르기까지 다양합니다. 나는 막대 차트로 두 가지가 더 쉽다고 주장합니다. 작은 세부 사항은 제목과 이름에 소문자를 사용하고 쉽게 % 기호를 반복하지 않는다는 것입니다. 나는 그것이 의미하는 바를 알지 못하고 컬러 코딩을 대략 모방 했으므로 복사 한 것과 마찬가지로 명확하거나 모호합니다.

트리 맵의 매력 중 일부는 상대적인 참신함에 있습니다. 수십 개의 이름이있는 경우 막 대형 차트보다 더 좋거나 더 효과적 일 수 있습니다.이 이름은 긴 열에 나열되지 않고 2 차원 영역에 분산 될 수 있습니다. 그러나 15 개 정도의 이름에 대해서는 막대 차트가 여전히 강력한 경쟁자로 남아 있습니다.

나는 (클리블랜드) 도트 차트를 선호하는 사람에게 기쁘게 생각합니다. 세로 막 대형 차트는 지역 이름을 편안하게 배치하기가 어렵습니다. 보수적 인 사람들은 그래프와 테이블 아이디어를 혼합하는 것을 좋아하지 않지만 나는 숫자를주는 아이디어를 좋아합니다.

그래프는 Stata로 그려졌습니다.


4
나는 그것을 파헤쳐 야 할 것이다. 그러나 만일 나의 기억이 나에게 올바르게 제공된다면 트리 맵의 원래 동기 중 하나는 정보의 계층 적 조직에 대한 것이었다 (즉, 계층의 다른 레벨의 결합 된 크기를 볼 수있게하는 것). 더 많은 숫자를 위해. 의도는 적은 수의 목록을위한 것이 아니며보다 탐구적인 호소력을 가졌다. 사각형 트리 맵을 만들기위한 지각 적 지침 ( Kong et al. 2010 )
Andy W

1
그것은 저의 인상이기도하므로 이름 트리 맵입니다. 여기서는 한 수준의 계층 만 분명합니다.
Nick Cox

4
Bill Shneiderman은 관련 서적 ( cs.umd.edu/hcil/treemap-history ) 에 대한 링크와 함께 멋진 트리 맵 기록을 작성했습니다 . 트리 맵은 처음에 덴드로 그램이나 트리보다 복잡하지 않은 방식으로 다단계 계층 구조를 표시하기위한 것이 었으며 처음에는 하드 디스크의 내용을 시각화하는 데 사용되었습니다. 오늘날 트리 맵은 다른 응용 분야 중에서 큰 계통 발생학 트리 (종 간의 관계를 보여줌)를 시각화하는 데 사용됩니다. 더 많은 예제를 보려면 perceptualedge.com/articles/b-eye/treemaps.pdf 에서 Shneiderman의 기사를 참조하십시오 .
JTT

감사; 가치가있는 것에 대해 나는이 특별한 경우에 동의합니다.
피터 엘리스

3

편집 / 추가

그 이후 트리 맵 패키지가 아래에 언급 된 (그리고 개조 된) map.market () 함수보다 훨씬 더 나은 결과를 제공 한다는 것을 발견했습니다 . 그러나 나는 역사적인 이유로 대답을 남길 것입니다.

원래 답변

답변 주셔서 감사합니다. @JTT에서 제공하는 흐르는 데이터 링크를 기반으로하지만 합리적인 그래픽을 얻기 위해 Illustrator 또는 Inkscape에서 직접 손으로 조정할 필요가 없도록하기 위해 Jeff Enos와 David Kane의 포트폴리오 패키지에서 map.market () 함수를 조정하여 더 많이 만들었습니다. 사용자가 제어하는 ​​레이블은 사각형 크기에 따라 다르며 적록 대비를 피하십시오. 사용법 예 :

library(portfolio)
library(extrafont)
data(dow.jan.2005)

with(dow.jan.2005, 
    treemap(id    = symbol,
        area  = price,
        group = sector,
        color = 100 * month.ret,
        labsc = .12,  # user-chosen scaling of labels 
        fontfamily="Comic Sans MS")
    )

여기에 이미지 설명을 입력하십시오

가치가있는 것에 대해, 나는 원래 질문의 예에서 도트 플롯이 우수하다는 @NickCox에 동의합니다. 내가 적응 한 treemap () 함수 코드는 다음과 같습니다.

treemap <- function (id, area, group, color, scale = NULL, lab = c(group = TRUE, 
    id = FALSE), low="red", middle="grey60", high="blue", main = "Map of the Market", labsc = c(.5, 1), print = TRUE, ...) 
{
    # Adapted by Peter Ellis from map.market() by Jeff Enos and David Kane in the portfolio package on CRAN
    # See map.market for the original helpfile.  The changes are:
    # 1. low, middle and high are user-set color ramp choices
    # 2. The font size now varies with the area of the rectangle being labelled; labsc is a scaling parameter to make it look ok.
    #    First element of labsc is scaling parameter for size of group labels.  Second element is scaling for id labels.
    # 3. ... extra arguments to be passed to gpar() when drawing labels; expected use is for fontfamily="whatever"
    require(portfolio)
    if (any(length(id) != length(area), length(id) != length(group), 
        length(id) != length(color))) {
        stop("id, area, group, and color must be the same length.")
    }
    if (length(lab) == 1) {
        lab[2] <- lab[1]
    }
    if (missing(id)) {
        id <- seq_along(area)
        lab["id"] <- FALSE
    }
    stopifnot(all(!is.na(id)))
    data <- data.frame(label = id, group, area, color)
    data <- data[order(data$area, decreasing = TRUE), ]
    na.idx <- which(is.na(data$area) | is.na(data$group) | is.na(data$color))
    if (length(na.idx)) {
        warning("Stocks with NAs for area, group, or color will not be shown")
        data <- data[-na.idx, ]
    }
    zero.area.idx <- which(data$area == 0)
    if (length(zero.area.idx)) {
        data <- data[-zero.area.idx, ]
    }
    if (nrow(data) == 0) {
        stop("No records to display")
    }
    data$color.orig <- data$color
    if (is.null(scale)) {
        data$color <- data$color * 1/max(abs(data$color))
    }
    else {
        data$color <- sapply(data$color, function(x) {
            if (x/scale > 1) 
                1
            else if (-1 > x/scale) 
                -1
            else x/scale
        })
    }
    data.by.group <- split(data, data$group, drop = TRUE)
    group.data <- lapply(data.by.group, function(x) {
        sum(x[, 3])
    })
    group.data <- data.frame(area = as.numeric(group.data), label = names(group.data))
    group.data <- group.data[order(group.data$area, decreasing = TRUE), 
        ]
    group.data$color <- rep(NULL, nrow(group.data))
    color.ramp.pos <- colorRamp(c(middle, high))
    color.ramp.neg <- colorRamp(c(middle, low))
    color.ramp.rgb <- function(x) {
        col.mat <- mapply(function(x) {
            if (x < 0) {
                color.ramp.neg(abs(x))
            }
            else {
                color.ramp.pos(abs(x))
            }
        }, x)
        mapply(rgb, col.mat[1, ], col.mat[2, ], col.mat[3, ], 
            max = 255)
    }
    add.viewport <- function(z, label, color, x.0, y.0, x.1, 
        y.1) {
        for (i in 1:length(label)) {
            if (is.null(color[i])) {
                filler <- gpar(col = "blue", fill = "transparent", 
                  cex = 1)
            }
            else {
                filler.col <- color.ramp.rgb(color[i])
                filler <- gpar(col = filler.col, fill = filler.col, 
                  cex = 0.6)
            }
            new.viewport <- viewport(x = x.0[i], y = y.0[i], 
                width = (x.1[i] - x.0[i]), height = (y.1[i] - 
                  y.0[i]), default.units = "npc", just = c("left", 
                  "bottom"), name = as.character(label[i]), clip = "on", 
                gp = filler)
            z <- append(z, list(new.viewport))
        }
        z
    }
    squarified.treemap <- function(z, x = 0, y = 0, w = 1, h = 1, 
        func = add.viewport, viewport.list) {
        cz <- cumsum(z$area)/sum(z$area)
        n <- which.min(abs(log(max(w/h, h/w) * sum(z$area) * 
            ((cz^2)/z$area))))
        more <- n < length(z$area)
        a <- c(0, cz[1:n])/cz[n]
        if (h > w) {
            viewport.list <- func(viewport.list, z$label[1:n], 
                z$color[1:n], x + w * a[1:(length(a) - 1)], rep(y, 
                  n), x + w * a[-1], rep(y + h * cz[n], n))
            if (more) {
                viewport.list <- Recall(z[-(1:n), ], x, y + h * 
                  cz[n], w, h * (1 - cz[n]), func, viewport.list)
            }
        }
        else {
            viewport.list <- func(viewport.list, z$label[1:n], 
                z$color[1:n], rep(x, n), y + h * a[1:(length(a) - 
                  1)], rep(x + w * cz[n], n), y + h * a[-1])
            if (more) {
                viewport.list <- Recall(z[-(1:n), ], x + w * 
                  cz[n], y, w * (1 - cz[n]), h, func, viewport.list)
            }
        }
        viewport.list
    }
    map.viewport <- viewport(x = 0.05, y = 0.05, width = 0.9, 
        height = 0.75, default.units = "npc", name = "MAP", just = c("left", 
            "bottom"))
    map.tree <- gTree(vp = map.viewport, name = "MAP", children = gList(rectGrob(gp = gpar(col = "dark grey"), 
        name = "background")))
    group.viewports <- squarified.treemap(z = group.data, viewport.list = list())
    for (i in 1:length(group.viewports)) {
        this.group <- data.by.group[[group.data$label[i]]]
        this.data <- data.frame(this.group$area, this.group$label, 
            this.group$color)
        names(this.data) <- c("area", "label", "color")
        stock.viewports <- squarified.treemap(z = this.data, 
            viewport.list = list())
        group.tree <- gTree(vp = group.viewports[[i]], name = group.data$label[i])
        for (s in 1:length(stock.viewports)) {
            stock.tree <- gTree(vp = stock.viewports[[s]], name = this.data$label[s], 
                children = gList(rectGrob(name = "color")))
            if (lab[2]) {
                stock.tree <- addGrob(stock.tree, textGrob(x = unit(1, 
                  "lines"), y = unit(1, "npc") - unit(1, "lines"), 
                  label = this.data$label[s], gp = gpar(col = "white", fontsize=this.data$area[s] * labsc[2], ...), 
                  name = "label", just = c("left", "top")))
            }
            group.tree <- addGrob(group.tree, stock.tree)
        }
        group.tree <- addGrob(group.tree, rectGrob(gp = gpar(col = "grey"), 
            name = "border"))
        if (lab[1]) {
            group.tree <- addGrob(group.tree, textGrob(label = group.data$label[i], 
                name = "label", gp = gpar(col = "white", fontsize=group.data$area[i] * labsc[1], ...)))
        }
        map.tree <- addGrob(map.tree, group.tree)
    }
    op <- options(digits = 1)
    top.viewport <- viewport(x = 0.05, y = 1, width = 0.9, height = 0.2, 
        default.units = "npc", name = "TOP", , just = c("left", 
            "top"))
    legend.ncols <- 51
    l.x <- (0:(legend.ncols - 1))/(legend.ncols)
    l.y <- unit(0.25, "npc")
    l.cols <- color.ramp.rgb(seq(-1, 1, by = 2/(legend.ncols - 
        1)))
    if (is.null(scale)) {
        l.end <- max(abs(data$color.orig))
    }
    else {
        l.end <- scale
    }
    top.list <- gList(textGrob(label = main, y = unit(0.7, "npc"), 
        just = c("center", "center"), gp = gpar(cex = 2, ...)), segmentsGrob(x0 = seq(0, 
        1, by = 0.25), y0 = unit(0.25, "npc"), x1 = seq(0, 1, 
        by = 0.25), y1 = unit(0.2, "npc")), rectGrob(x = l.x, 
        y = l.y, width = 1/legend.ncols, height = unit(1, "lines"), 
        just = c("left", "bottom"), gp = gpar(col = NA, fill = l.cols), 
        default.units = "npc"), textGrob(label = format(l.end * 
        seq(-1, 1, by = 0.5), trim = TRUE), x = seq(0, 1, by = 0.25), 
        y = 0.1, default.units = "npc", just = c("center", "center"), 
        gp = gpar(col = "black", cex = 0.8, fontface = "bold")))
    options(op)
    top.tree <- gTree(vp = top.viewport, name = "TOP", children = top.list)
    mapmarket <- gTree(name = "MAPMARKET", children = gList(rectGrob(gp = gpar(col = "dark grey", 
        fill = "dark grey"), name = "background"), top.tree, 
        map.tree))
    if (print) {
        grid.newpage()
        grid.draw(mapmarket)
    }
    invisible(mapmarket)
}

이 코드는 의심 할 여지가 없습니다. 토론을 진행하지 않을 영역으로 드래그하고 싶지는 않지만 예제가 임의적이거나 해당 영역을 주가로 표시하게하는 근거가 있습니까? 이 음모에서 무엇을 보거나 찾아야합니까? (나는 많은 사례를 보았지만이 디자인을 실제로 사용하는 데 전혀 경험이없는 적대적이지 않다.)
Nick Cox

1
실제로 Enos와 Kane의 map.market () 도움말 파일에서 예제를 보았습니다. 그것에 반영 나는 왜 그들이 지역 쇼 가격을 갖기로 선택했는지 보지 못한다. 보다 합리적인 척도는 총 자본화, 즉 가격 x 주식 수 (시장의 주식 수 또는 목적에 따라 내가 소유 한 주식 수)를 보여주는 것입니다. 그런 다음 다른 주식의 중요성을 보여주기 위해 플롯을 직관적으로 잘 사용합니다.
피터 엘리스

나는 가격을 사용하여 너무 당황했다.
Nick Cox

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.