Có tên cho biểu đồ này không - sắp xếp chéo giữa biểu đồ hình tròn và biểu đồ mekko


9

Có một tên cho loại biểu đồ này dưới đây (có nguồn gốc từ Bộ Kinh doanh, Đổi mới và Việc làm của New Zealand , người mà tôi làm việc nhưng tôi không tham gia vào việc tạo ra âm mưu này)? Nó bao gồm các hình chữ nhật trong đó diện tích tỷ lệ với một biến và giống như một loại hình chéo giữa biểu đồ hình tròn, biểu đồ khảm và biểu đồ mekko. Nó có lẽ là gần nhất với một âm mưu mekko nhưng có một điều phức tạp là chúng ta không làm việc với các cột mà là một trò ghép hình phức tạp hơn.

Bản gốc trông tốt hơn một chút vì có các đường viền màu trắng giữa các hình chữ nhật cho từng vùng.

Đáng ngạc nhiên, nó thực sự gây ấn tượng với tôi như một đồ họa thống kê không quá tệ, mặc dù nó có thể được cải thiện thông qua việc sử dụng tốt hơn màu sắc được ánh xạ tới một cái gì đó có ý nghĩa. Một phiên bản tương tác mạnh mẽ cho thấy ngân sách Hoa Kỳ 2011 đã được New York Times sử dụng .

Một thách thức thú vị là nghĩ ra một thuật toán tự động để vẽ một thuật toán và làm cho nó trông hợp lý. Các hình chữ nhật cần phải được phép có các tỷ lệ khung hình khác nhau, trong phạm vi chấp nhận được.

nhập mô tả hình ảnh ở đây


Kết quả cuối cùng của dự án bắt đầu với câu hỏi này có thể được nhìn thấy trong công cụ web tương tác được liên kết từ đây: mbie.govt.nz/what-we-do/business-growth-agenda/regions
Peter Ellis

Câu trả lời:



12

Câu hỏi là tên, nhưng nó hoạt động tốt như thế nào cũng là mở để thảo luận.

Đây là một cái gì đó prosaic hơn như là một thay thế, một biểu đồ thanh ngang.

nhập mô tả hình ảnh ở đây

Những gì chúng ta có thể muốn làm với một biểu đồ như vậy thay đổi từ một số nắm bắt của mô hình tổng thể đến một số nghiên cứu kỹ lưỡng về các trường hợp riêng lẻ (những gì về Vịnh Hawke, v.v.). Tôi khẳng định rằng cả hai đều dễ dàng hơn với biểu đồ thanh. Chi tiết nhỏ là tôi sử dụng chữ thường trong tiêu đề và tên dễ dàng và không lặp lại ký hiệu%. Tôi gần như đã bắt chước mã màu mà không tìm hiểu ý nghĩa của nó, vì vậy nó rõ ràng hoặc tối nghĩa như những gì bạn đã sao chép.

Tôi đề nghị rằng một số sự hấp dẫn của treemaps nằm ở sự mới lạ tương đối của chúng. Chúng có thể hoạt động tốt hơn hoặc tốt hơn biểu đồ thanh nếu có hàng tá tên, có thể được trải rộng trên một khu vực hai chiều thay vì được liệt kê trong một cột dài. Nhưng đối với 15 cái tên như vậy, một biểu đồ thanh vẫn là một đối thủ cạnh tranh mạnh mẽ trong quan điểm của tôi.

Tôi hạnh phúc với bất cứ ai thích biểu đồ chấm (Cleveland) ở đây. Một biểu đồ thanh dọc sẽ đối mặt với khó khăn trong việc đặt tên khu vực một cách thoải mái. (Chỉ cần tưởng tượng xoay biểu đồ này để thấy điều đó.) Tôi cũng thích ý tưởng đưa ra các con số, mặc dù những người bảo thủ không thích trộn các biểu đồ và ý tưởng bảng.

Biểu đồ được vẽ ở Stata.


4
Tôi sẽ phải khai thác nó, nhưng nếu bộ nhớ của tôi phục vụ cho tôi một cách chính xác thì một trong những động lực ban đầu của bản đồ cây là dành cho một tổ chức thông tin phân cấp (nghĩa là cho phép bạn xem kích thước kết hợp của các cấp khác nhau của phân cấp) và cho nhiều số hơn Mục đích không bao giờ dành cho các danh sách nhỏ về các con số và có sức hấp dẫn khám phá nhiều hơn, xem Hướng dẫn nhận thức để tạo Treemaps hình chữ nhật ( Kong et al. 2010 )
Andy W

1
Đó cũng là ấn tượng của tôi, do đó có tên treemap. Chỉ có một cấp độ của một hệ thống phân cấp là rõ ràng ở đây.
Nick Cox

4
Bill Shneerman đã kết hợp một lịch sử tốt đẹp của treemaps với các liên kết đến một số ấn phẩm có liên quan ( cs.umd.edu/hcil/treemap-history ). Treemaps ban đầu được dự định để hiển thị một hệ thống phân cấp đa cấp theo cách ít lộn xộn hơn so với dendrogram hoặc cây có thể, và lúc đầu chúng được sử dụng để hiển thị nội dung của đĩa cứng. Ngày nay, treemaps được sử dụng để trực quan hóa các cây phát sinh gen lớn (chúng cho thấy mối quan hệ giữa các loài), trong số các ứng dụng khác. Để biết thêm ví dụ, hãy xem bài viết của Shneerman tại perceptualedge.com/articles/b-eye/treemaps.pdf .
JTT

Cảm ơn; Đối với những gì nó có giá trị tôi đồng ý trong trường hợp cụ thể này.
Peter Ellis

3

Chỉnh sửa / bổ sung

Kể từ đó, tôi đã phát hiện ra rằng gói treemap cho kết quả tốt hơn nhiều so với hàm map.market () được đề cập (và điều chỉnh) bên dưới; nhưng tôi sẽ để lại câu trả lời của tôi vì lý do lịch sử.

Câu trả lời gốc

Cảm ơn câu trả lời. Dựa trên liên kết dữ liệu đang được cung cấp bởi @JTT nhưng không thích điều chỉnh bằng tay trong Illustrator hoặc Inkscape chỉ để có được một đồ họa hợp lý, tôi đã điều chỉnh chức năng map.market () trong gói danh mục đầu tư của Jeff Enos và David Kane để làm cho nó nhiều hơn do người dùng kiểm soát, các nhãn thay đổi theo kích thước hình chữ nhật và tránh sự tương phản màu đỏ-xanh. Ví dụ sử dụng:

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")
    )

nhập mô tả hình ảnh ở đây

Đối với những gì nó có giá trị, tôi cũng đồng ý với @NickCox rằng trong ví dụ trong câu hỏi ban đầu của tôi, một âm mưu chấm là vượt trội. Mã của hàm treemap () được điều chỉnh của tôi theo sau.

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)
}

Mã đó chắc chắn sẽ hữu ích. Tôi không muốn kéo cuộc thảo luận vào các khu vực mà nó sẽ không đi, nhưng ví dụ này có khá độc đoán hay có lý do nào để cho các khu vực đại diện cho giá cổ phiếu không? Chúng ta phải thấy gì hoặc đang tìm kiếm gì trên cốt truyện này? (Tôi không thù địch, hoàn toàn không có kinh nghiệm với việc cố gắng sử dụng thiết kế này thực sự, mặc dù tôi đã thấy rất nhiều ví dụ.)
Nick Cox

1
Thật ra tôi chỉ lấy ví dụ từ tệp trợ giúp cho map.market () của Enos và Kane. Suy nghĩ về điều đó tôi không thấy lý do tại sao họ chọn có giá hiển thị khu vực; một biện pháp hợp lý hơn chắc chắn sẽ là hiển thị tổng vốn hóa, tức là giá x số lượng cổ phiếu (số lượng cổ phiếu trên thị trường, hoặc chỉ số lượng cổ phiếu tôi tình cờ sở hữu tùy thuộc vào mục đích). Sau đó, bạn sẽ có một cách sử dụng trực quan tốt của cốt truyện để cho thấy tầm quan trọng của các cổ phiếu khác nhau.
Peter Ellis

Tôi đã rất bối rối bởi việc sử dụng giá cả.
Nick Cox

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.