用pandas

时间:2017-03-18 18:48:36

标签: pandas matplotlib radar-chart

我正试图通过创建像this question州这样的雷达图来更进一步。我使用上一个问题使用的相同源code,除了我试图使用pandas dataframe和pivot表实现它。

import numpy as np
import pandas as pd
from StringIO import StringIO

import matplotlib.pyplot as plt
from matplotlib.projections.polar import PolarAxes
from matplotlib.projections import register_projection


def radar_factory(num_vars, frame='circle'):
    """Create a radar chart with `num_vars` axes."""
    # calculate evenly-spaced axis angles
    theta = 2 * np.pi * np.linspace(0, 1 - 1. / num_vars, num_vars)
    # rotate theta such that the first axis is at the top
    theta += np.pi / 2

    def draw_poly_frame(self, x0, y0, r):
        # TODO: use transforms to convert (x, y) to (r, theta)
        verts = [(r * np.cos(t) + x0, r * np.sin(t) + y0) for t in theta]
        return plt.Polygon(verts, closed=True, edgecolor='k')

    def draw_circle_frame(self, x0, y0, r):
        return plt.Circle((x0, y0), r)

    frame_dict = {'polygon': draw_poly_frame, 'circle': draw_circle_frame}
    if frame not in frame_dict:
        raise ValueError, 'unknown value for `frame`: %s' % frame

    class RadarAxes(PolarAxes):
        """Class for creating a radar chart (a.k.a. a spider or star chart)
        http://en.wikipedia.org/wiki/Radar_chart
        """
        name = 'radar'
        # use 1 line segment to connect specified points
        RESOLUTION = 1
        # define draw_frame method
        draw_frame = frame_dict[frame]

        def fill(self, *args, **kwargs):
            """Override fill so that line is closed by default"""
            closed = kwargs.pop('closed', True)
            return super(RadarAxes, self).fill(closed=closed, *args, **kwargs)

        def plot(self, *args, **kwargs):
            """Override plot so that line is closed by default"""
            lines = super(RadarAxes, self).plot(*args, **kwargs)
            for line in lines:
                self._close_line(line)

        def _close_line(self, line):
            x, y = line.get_data()
            # FIXME: markers at x[0], y[0] get doubled-up
            if x[0] != x[-1]:
                x = np.concatenate((x, [x[0]]))
                y = np.concatenate((y, [y[0]]))
                line.set_data(x, y)

        def set_varlabels(self, labels):
            self.set_thetagrids(theta * 180 / np.pi, labels)

        def _gen_axes_patch(self):
            x0, y0 = (0.5, 0.5)
            r = 0.5
            return self.draw_frame(x0, y0, r)

    register_projection(RadarAxes)
    return theta

def day_radar_plot(df):
    fig = plt.figure(figsize=(6,6))
    #adjust spacing around the subplots
    fig.subplots_adjust(wspace=0.25,hspace=0.20,top=0.85,bottom=0.05)

    ldo,rup = 0.1,0.8         #leftdown and right up normalized

    ax = fig.add_axes([ldo,ldo,rup,rup],polar=True)

    N = len(df['Group1'].unique())
    theta = radar_factory(N)

    polar_df = pd.DataFrame(df.groupby([df['Group1'],df['Type'],df['Vote']]).size())
    polar_df.columns = ['Count']

    radii = polar_df['Count'].get_values()
    names = polar_df.index.get_values()

    #get the number of unique colors needed
    num_colors_needed = len(names)

    #Create the list of unique colors needed for red and blue shades
    Rcolors = []
    Gcolors = []

    for i in range(num_colors_needed):
        ri=1-(float(i)/float(num_colors_needed))
        gi=0.
        bi=0.

        Rcolors.append((ri,gi,bi))

    for i in range(num_colors_needed):
        ri=0.
        gi=1-(float(i)/float(num_colors_needed))
        bi=0.

        Gcolors.append((ri,gi,bi))

    from_x  = np.linspace(0,0.95,num_colors_needed)
    to_x = from_x + 0.05

    i = 0

    for d,f,R,G in zip(radii,polar_df.index,Rcolors,Gcolors):
        i = i+1
        if f[2].lower() == 'no':
            ax.plot(theta,d,color=R)
            ax.fill(theta,d,facecolor=R,alpha=0.25)

            #this is where I think i have the issue
            ax.axvspan(from_x[i],to_x[i],color=R)

        elif f[2].lower() == 'yes':
            ax.plot(theta,d,color=G)
            ax.fill(theta,d,facecolor=G,alpha=0.25)

            #this is where I think i have the issue
            ax.axvspan(from_x[i],to_x[i],color=G)



    plt.show()

所以,让我说我的StringIO有一个Group1投票列表是或否,它们来自编号类型......这些数字在标签中是任意的,但仅作为示例..

fakefile = StringIO("""\
Group1,Type,Vote
James,7,YES\nRachael,7,YES\nChris,2,YES\nRachael,9,NO
Chris,2,YES\nChris,7,NO\nRachael,9,NO\nJames,2,NO
James,7,NO\nJames,9,YES\nRachael,9,NO
Chris,2,YES\nChris,2,YES\nRachael,7,NO
Rachael,7,YES\nJames,9,YES\nJames,9,NO
Rachael,2,NO\nChris,2,YES\nRachael,7,YES
Rachael,9,NO\nChris,9,NO\nJames,7,NO
James,2,YES\nChris,2,NO\nRachael,9,YES
Rachael,9,YES\nRachael,2,NO\nChris,7,YES
James,7,YES\nChris,9,NO\nRachael,9,NO\n
Chris,9,YES
""")

record = pd.read_csv(fakefile, header=0)
day_radar_plot(record)

我得到的错误是Value Error: x and y must have same first dimension。 正如我在剧本中指出的那样,我认为我有一个解决方案,但显然我会以错误的方式去做。有没有人有任何建议或指导?

1 个答案:

答案 0 :(得分:4)

由于我完全迷失了你想要做的事情,我将简单地提供一个如何从给定数据中绘制雷达图的解决方案。

它将回答人们多长时间选票是或否的问题。

enter image description here

import pandas as pd
import numpy as np
from StringIO import StringIO
import matplotlib.pyplot as plt


fakefile = StringIO("""\
Group1,Type,Vote
James,7,YES\nRachael,7,YES\nChris,2,YES\nRachael,9,NO
Chris,2,YES\nChris,7,NO\nRachael,9,NO\nJames,2,NO
James,7,NO\nJames,9,YES\nRachael,9,NO
Chris,2,YES\nChris,2,YES\nRachael,7,NO
Rachael,7,YES\nJames,9,YES\nJames,9,NO
Rachael,2,NO\nChris,2,YES\nRachael,7,YES
Rachael,9,NO\nChris,9,NO\nJames,7,NO
James,2,YES\nChris,2,NO\nRachael,9,YES
Rachael,9,YES\nRachael,2,NO\nChris,7,YES
James,7,YES\nChris,9,NO\nRachael,9,NO\n
Chris,9,YES""")

df = pd.read_csv(fakefile, header=0)
df["cnt"] = np.ones(len(df))

pt = pd.pivot_table(df, values='cnt', index=['Group1'],
                  columns=['Vote'], aggfunc=np.sum)

fig = plt.figure()
ax = fig.add_subplot(111, projection="polar")

theta = np.arange(len(pt))/float(len(pt))*2.*np.pi
l1, = ax.plot(theta, pt["YES"], color="C2", marker="o", label="YES")
l2, = ax.plot(theta, pt["NO"], color="C3", marker="o", label="NO")

def _closeline(line):
    x, y = line.get_data()
    x = np.concatenate((x, [x[0]]))
    y = np.concatenate((y, [y[0]]))
    line.set_data(x, y)
[_closeline(l) for l in [l1,l2]]

ax.set_xticks(theta)
ax.set_xticklabels(pt.index)
plt.legend()
plt.title("How often have people votes Yes or No?")
plt.show()