2016-10-23 2 views
0

Ich möchte ein Radardiagramm mit Legenden für jedes erstellte Diagramm erstellen, aber bis jetzt war es unmöglich. Dann können Sie den Code sehen, der zum Erstellen des Diagramms verwendet wurde (dank eines anderen Benutzers, der es entwickelt hat).Legende zu einem Radarchart in Python hinzufügen

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

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) 

Jede Handlung repräsentiert verschiedene Menschen. Ich möchte eine Legende hinzufügen, die den Namen von allen und die Farbe, die ihn in der Handlung darstellt, zeigt. Ich habe versucht, Labels und dann die Legenden hinzuzufügen, aber es hat nicht funktioniert. Das Grundstück produziert ist so etwas wie das:

df = pd.DataFrame({ 
    "Spe": pd.Series([89, 83, 70, 60, 30, 49, 28]), 
    "Str": pd.Series([69, 53, 30, 20, 10, 29, 48]), 
    "Det": pd.Series([82, 44, 79, 39, 20, 10, 85]), 
    "Extr": pd.Series([59, 74, 29, 36, 18, 29, 18]), 
    "Int": pd.Series([63, 11, 20, 36, 97, 58, 91]), 
    "Est": pd.Series([12, 69, 89, 59, 19, 58, 98]), 
    "Ape": pd.Series([29, 13, 94, 30, 20, 10, 67]), 
    "ID": pd.Series(["Carl","Michael","Peter","Louis","Sarah", 
        "Laura","Nicholas"]) 
}) 
dfo = df.drop('ID', 1) 
print(dfo) 

variables = ("1", "2", "3", 
     "4", "5", "6", "7") 
ranges = [(1,100),(1,100),(1,100),(1,100),(1,100),(1,100),(1,100)] 
fig1 = plt.figure(figsize=(8, 8)) 
radar = ComplexRadar(fig1, variables, ranges) 
for i in range(len(dfo.index)-1): 
    data=dfo.iloc[i,:] 
    radar.plot(data) 
    radar.fill(data,alpha=0.2) 
sns.plt.show() 

Link to plot produced

Vielen Dank für Ihre Hilfe.

Antwort

0

Falls jemand interessiert ist, kommt der Code des ComplexRadar von here.
Die ComplexRadar Klasse verwendet viele Achsen und macht sie alle unsichtbar, also wäre der beste Weg, um hier eine Legende zu erstellen, eine neue Achse zu erstellen, um die Legende einzufügen. Dafür brauchen wir die Griffe der gezeichneten Linien, also Wir müssen die ComplexRadar.plot() Methode ändern, um die Linie zurückzugeben. Wir müssen dann diese Zeilen in einer Liste sammeln (nennen Sie es lax) und sie an die neue Legende liefern.

Ich habe einige Änderungen am Code vorgenommen, damit er in Python 2.7 funktioniert und ich ihn auch verständlicher mache. Hier ist, was funktionieren sollte:

import numpy as np 
import matplotlib.pyplot as plt 
import seaborn as sns 
import pandas as pd 

def _scale_data(data, ranges): 
    """scales data[1:] to ranges[0], 
    """ 
    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] 
    sdata = [d] 
    for d, (y1, y2) in zip(data[1:], ranges[1:]): 
     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) 
     l = self.ax.plot(self.angle, np.r_[sdata, sdata[0]], *args, **kw) 
     return l 

    def fill(self, data, *args, **kw): 
     sdata = _scale_data(data, self.ranges) 
     self.ax.fill(self.angle, np.r_[sdata, sdata[0]], *args, **kw) 



index = ["Carl","Michael","Peter","Louis","Sarah", "Laura","Nicholas"]  
df = pd.DataFrame({ 
    "Spe": pd.Series([89, 83, 70, 60, 30, 49, 28]), 
    "Str": pd.Series([69, 53, 30, 20, 10, 29, 48]), 
    "Det": pd.Series([82, 44, 79, 39, 20, 10, 85]), 
    "Extr": pd.Series([59, 74, 29, 36, 18, 29, 18]), 
    "Int": pd.Series([63, 11, 20, 36, 97, 58, 91]), 
    "Est": pd.Series([12, 69, 89, 59, 19, 58, 98]), 
    "Ape": pd.Series([29, 13, 94, 30, 20, 10, 67]), 
}) 

variables = [k[0] for k in df.iteritems()] 

ranges = [(1.,100.),(1.,100.),(1.,100.),(1.,100.),(1.,100.),(1.,100.),(1.,100.)] 
fig1 = plt.figure(figsize=(8, 8)) 
radar = ComplexRadar(fig1, variables, ranges) 
lax = [] 
for i, name in enumerate(index): 
    data=df.iloc[i].values 
    l, = radar.plot(data, label=name) 
    lax.append(l) 
    radar.fill(data,alpha=0.2) 

legendax = fig1.add_axes([0.8,0.8,0.1,.1]) 
legendax.legend(handles = lax, labels=index, loc=3, bbox_to_anchor=(0,0,1,1), bbox_transform=fig1.transFigure) 

legendax.axis('off') 
sns.plt.show() 

dabei die folgende Handlung enter image description here

+0

Thank you very much. Vielleicht weißt du, was ich tun muss, um den Code in JS umzuwandeln? Ich versuche, Bokeh zu verwenden, aber wenn es mir die HTML-Version der Handlung zeigt, ist es nur eine leere Zahl. – Stacatt

+0

Ich denke, die Frage, wie man das im Bokeh macht, ist eine andere. Vielleicht möchten Sie eine neue Frage dazu stellen und Ihren Bokeh-Code anzeigen. Ich bin kein Experte in Bokeh, also denke ich, dass ich nicht helfen kann, aber jemand anderes kann. – ImportanceOfBeingErnest

+0

Ok, ich werde es tun. Letzte Frage (Es tut mir leid, dass ich so nervig bin, aber ich lerne Python noch), in diesem Fall, wie kann ich die Farben ändern? Ich habe versucht, die sns.color_palette() an verschiedenen Stellen des Codes hinzuzufügen, aber es hat nicht funktioniert. – Stacatt

Verwandte Themen