ฉันจะสร้างแผนภูมิเรดาร์ที่ซับซ้อนได้อย่างไร


19

ดังนั้นฉันต้องการสร้างแผนภูมิเรดาร์โปรไฟล์ผู้เล่นดังนี้:


ป้อนคำอธิบายรูปภาพที่นี่


ไม่เพียง แต่สเกลของแต่ละตัวแปรที่แตกต่างกัน แต่ฉันต้องการสเกลที่กลับด้านสำหรับสถิติบางอย่างเช่นสถิติ 'ยึดทรัพย์' ซึ่งจริงๆแล้วหมายถึงน้อย

ทางออกหนึ่งสำหรับสเกลตัวแปรสำหรับแต่ละสถิติอาจเป็นการกำหนดเกณฑ์มาตรฐานแล้วคำนวณคะแนนในระดับ 100 หรือไม่

แต่ฉันจะแสดงตัวเลขจริงบนแผนภูมิได้อย่างไร นอกจากนี้ฉันจะได้รับมาตราส่วนกลับด้านสำหรับสถิติบางส่วนได้อย่างไร

กำลังทำงานใน Excel เครื่องมือที่ทรงพลังที่สุดในการสร้างแผนภูมิที่ซับซ้อนเช่นนี้คืออะไร?


คุณสามารถยกตัวอย่างของชุดข้อมูลที่คุณพยายามจะจินตนาการได้หรือไม่? ขณะนี้คำถามของคุณไม่ชัดเจน ให้ชุดข้อมูลตัวอย่างและพล็อตที่เกี่ยวข้องที่คุณต้องการดูจะช่วย นอกจากนี้การให้ลิงก์ภายนอก (โดยเฉพาะจากเว็บไซต์ชั่วคราวเช่น twitter) จึงไม่ควรลองอธิบายให้ดีที่สุดเท่าที่จะทำได้
Nitesh

1
Excel เป็นสิ่งที่ดีที่สุด (ภาพที่สวยที่สุด)! คุณสามารถค้นหาการติดตั้งใช้งานในภาษาไพ ธ อนหรือภาษาอื่น ๆ ฉันลองมาหนึ่งเดือนแล้ว!
Kasra Manshaei

ทางออกของ Kyler นั้นยอดเยี่ยม แต่ไม่สมบูรณ์ โค้ดด้านบนมีการพล็อตเฉพาะจุดบน 6 แกน ... ค่า 20 สำหรับแกน "Inverted 3%" ไม่ได้พล็อตเมื่อฉันรันสิ่งนี้

คำตอบ:


13

ว้าวนี่มันท้าทายนิดหน่อย แต่ฉันก็สามารถแปลงหนึ่งในไพ ธ อนได้ ส่วนประกอบหลักที่สอง:

รหัส :

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns # improves plot aesthetics


def _invert(x, limits):
    """inverts a value x on a scale from
    limits[0] to limits[1]"""
    return limits[1] - (x - limits[0])

def _scale_data(data, ranges):
    """scales data[1:] to ranges[0],
    inverts if the scale is reversed"""
    for d, (y1, y2) in zip(data[1:], ranges[1:]):
        assert (y1 <= d <= y2) or (y2 <= d <= y1)
    x1, x2 = ranges[0]
    d = data[0]
    if x1 > x2:
        d = _invert(d, (x1, x2))
        x1, x2 = x2, x1
    sdata = [d]
    for d, (y1, y2) in zip(data[1:], ranges[1:]):
        if y1 > y2:
            d = _invert(d, (y1, y2))
            y1, y2 = y2, y1
        sdata.append((d-y1) / (y2-y1) 
                     * (x2 - x1) + x1)
    return sdata

class ComplexRadar():
    def __init__(self, fig, variables, ranges,
                 n_ordinate_levels=6):
        angles = np.arange(0, 360, 360./len(variables))

        axes = [fig.add_axes([0.1,0.1,0.9,0.9],polar=True,
                label = "axes{}".format(i)) 
                for i in range(len(variables))]
        l, text = axes[0].set_thetagrids(angles, 
                                         labels=variables)
        [txt.set_rotation(angle-90) for txt, angle 
             in zip(text, angles)]
        for ax in axes[1:]:
            ax.patch.set_visible(False)
            ax.grid("off")
            ax.xaxis.set_visible(False)
        for i, ax in enumerate(axes):
            grid = np.linspace(*ranges[i], 
                               num=n_ordinate_levels)
            gridlabel = ["{}".format(round(x,2)) 
                         for x in grid]
            if ranges[i][0] > ranges[i][1]:
                grid = grid[::-1] # hack to invert grid
                          # gridlabels aren't reversed
            gridlabel[0] = "" # clean up origin
            ax.set_rgrids(grid, labels=gridlabel,
                         angle=angles[i])
            #ax.spines["polar"].set_visible(False)
            ax.set_ylim(*ranges[i])
        # variables for plotting
        self.angle = np.deg2rad(np.r_[angles, angles[0]])
        self.ranges = ranges
        self.ax = axes[0]
    def plot(self, data, *args, **kw):
        sdata = _scale_data(data, self.ranges)
        self.ax.plot(self.angle, np.r_[sdata, sdata[0]], *args, **kw)
    def fill(self, data, *args, **kw):
        sdata = _scale_data(data, self.ranges)
        self.ax.fill(self.angle, np.r_[sdata, sdata[0]], *args, **kw)

# example data
variables = ("Normal Scale", "Inverted Scale", "Inverted 2", 
            "Normal Scale 2", "Normal 3", "Normal 4 %", "Inverted 3 %")
data = (1.76, 1.1, 1.2, 
        4.4, 3.4, 86.8, 20)
ranges = [(0.1, 2.3), (1.5, 0.3), (1.3, 0.5),
         (1.7, 4.5), (1.5, 3.7), (70, 87), (100, 10)]            
# plotting
fig1 = plt.figure(figsize=(6, 6))
radar = ComplexRadar(fig1, variables, ranges)
radar.plot(data)
radar.fill(data, alpha=0.2)
plt.show()    

6

นี่คือเวอร์ชั่น R:

รหัสที่นี่ดูเหมือนล้าสมัยสำหรับ ggplot2: 2.0.0

ลองแพ็คเกจของฉัน zmisc: devtools:install_github("jerryzhujian9/ezmisc")

หลังจากคุณติดตั้งแล้วคุณจะสามารถเรียกใช้:

df = mtcars
df$model = rownames(mtcars)

ez.radarmap(df, "model", stats="mean", lwd=1, angle=0, fontsize=0.6, facet=T, facetfontsize=1, color=id, linetype=NULL)
ez.radarmap(df, "model", stats="none", lwd=1, angle=0, fontsize=1.5, facet=F, facetfontsize=1, color=id, linetype=NULL)

รหัสหลักถูกดัดแปลงจากhttp://www.cmap.polytechnique.fr/~lepennec/R/Radar/RadarAndParallelPlots.html

ป้อนคำอธิบายรูปภาพที่นี่


3

นี่คือการแก้ไขเล็กน้อยของKyler Brown สำหรับ Pythonที่อนุญาตให้ค่าลบในแกนขั้วโลก ( ซึ่งปัจจุบันไม่ได้รับการสนับสนุนอย่างเป็นทางการโดย matplotlib ) โดยทั่วไปเพียงแค่ลบเช็คสำหรับค่าลบออกจากset_rgrids:

พล็อต

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns # improves plot aesthetics


def _invert(x, limits):
    """inverts a value x on a scale from
    limits[0] to limits[1]"""
    return limits[1] - (x - limits[0])

def _scale_data(data, ranges):
    """scales data[1:] to ranges[0],
    inverts if the scale is reversed"""
    # for d, (y1, y2) in zip(data[1:], ranges[1:]):
    for d, (y1, y2) in zip(data, ranges):
        assert (y1 <= d <= y2) or (y2 <= d <= y1)

    x1, x2 = ranges[0]
    d = data[0]

    if x1 > x2:
        d = _invert(d, (x1, x2))
        x1, x2 = x2, x1

    sdata = [d]

    for d, (y1, y2) in zip(data[1:], ranges[1:]):
        if y1 > y2:
            d = _invert(d, (y1, y2))
            y1, y2 = y2, y1

        sdata.append((d-y1) / (y2-y1) * (x2 - x1) + x1)

    return sdata

def set_rgrids(self, radii, labels=None, angle=None, fmt=None,
               **kwargs):
    """
    Set the radial locations and labels of the *r* grids.
    The labels will appear at radial distances *radii* at the
    given *angle* in degrees.
    *labels*, if not None, is a ``len(radii)`` list of strings of the
    labels to use at each radius.
    If *labels* is None, the built-in formatter will be used.
    Return value is a list of tuples (*line*, *label*), where
    *line* is :class:`~matplotlib.lines.Line2D` instances and the
    *label* is :class:`~matplotlib.text.Text` instances.
    kwargs are optional text properties for the labels:
    %(Text)s
    ACCEPTS: sequence of floats
    """
    # Make sure we take into account unitized data
    radii = self.convert_xunits(radii)
    radii = np.asarray(radii)
    rmin = radii.min()
    # if rmin <= 0:
    #     raise ValueError('radial grids must be strictly positive')

    self.set_yticks(radii)
    if labels is not None:
        self.set_yticklabels(labels)
    elif fmt is not None:
        self.yaxis.set_major_formatter(FormatStrFormatter(fmt))
    if angle is None:
        angle = self.get_rlabel_position()
    self.set_rlabel_position(angle)
    for t in self.yaxis.get_ticklabels():
        t.update(kwargs)
    return self.yaxis.get_gridlines(), self.yaxis.get_ticklabels()

class ComplexRadar():
    def __init__(self, fig, variables, ranges,
                 n_ordinate_levels=6):
        angles = np.arange(0, 360, 360./len(variables))

        axes = [fig.add_axes([0.1,0.1,0.9,0.9],polar=True,
                label = "axes{}".format(i)) 
                for i in range(len(variables))]
        l, text = axes[0].set_thetagrids(angles, 
                                         labels=variables)
        [txt.set_rotation(angle-90) for txt, angle 
             in zip(text, angles)]
        for ax in axes[1:]:
            ax.patch.set_visible(False)
            ax.grid("off")
            ax.xaxis.set_visible(False)
        for i, ax in enumerate(axes):
            grid = np.linspace(*ranges[i], 
                               num=n_ordinate_levels)
            gridlabel = ["{}".format(round(x,2)) 
                         for x in grid]
            if ranges[i][0] > ranges[i][1]:
                grid = grid[::-1] # hack to invert grid
                          # gridlabels aren't reversed
            gridlabel[0] = "" # clean up origin
            # ax.set_rgrids(grid, labels=gridlabel, angle=angles[i])
            set_rgrids(ax, grid, labels=gridlabel, angle=angles[i])
            #ax.spines["polar"].set_visible(False)
            ax.set_ylim(*ranges[i])
        # variables for plotting
        self.angle = np.deg2rad(np.r_[angles, angles[0]])
        self.ranges = ranges
        self.ax = axes[0]
    def plot(self, data, *args, **kw):
        sdata = _scale_data(data, self.ranges)
        self.ax.plot(self.angle, np.r_[sdata, sdata[0]], *args, **kw)
    def fill(self, data, *args, **kw):
        sdata = _scale_data(data, self.ranges)
        self.ax.fill(self.angle, np.r_[sdata, sdata[0]], *args, **kw)

# example data
variables = ("Normal Scale", "Inverted Scale", "Inverted 2", 
            "Normal Scale 2", "Normal 3", "Normal 4 %", "Inverted 3 %")
data = (-1.76, 1.1, 1.2, 
        4.4, 3.4, 86.8, 20)
ranges = [(-5, 3), (1.5, 0.3), (1.3, 0.5),
         (1.7, 4.5), (1.5, 3.7), (70, 87), (100, -50)]            
# plotting
fig1 = plt.figure(figsize=(6, 6))
radar = ComplexRadar(fig1, variables, ranges)
radar.plot(data)
radar.fill(data, alpha=0.2)
plt.show()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.