1

I would like to reproduce the radar chart described here

The main difference is that my data have two different spoke_labels

import numpy as np

import matplotlib.pyplot as plt
from matplotlib.patches import Circle, RegularPolygon
from matplotlib.path import Path
from matplotlib.projections.polar import PolarAxes
from matplotlib.projections import register_projection
from matplotlib.spines import Spine
from matplotlib.transforms import Affine2D


def radar_factory(num_vars, frame='circle'):
    """
    Create a radar chart with `num_vars` axes.

    This function creates a RadarAxes projection and registers it.

    Parameters
    ----------
    num_vars : int
        Number of variables for radar chart.
    frame : {'circle', 'polygon'}
        Shape of frame surrounding axes.

    """
    # calculate evenly-spaced axis angles
    theta = np.linspace(0, 2*np.pi, num_vars, endpoint=False)

    class RadarTransform(PolarAxes.PolarTransform):

        def transform_path_non_affine(self, path):
            # Paths with non-unit interpolation steps correspond to gridlines,
            # in which case we force interpolation (to defeat PolarTransform's
            # autoconversion to circular arcs).
            if path._interpolation_steps > 1:
                path = path.interpolated(num_vars)
            return Path(self.transform(path.vertices), path.codes)

    class RadarAxes(PolarAxes):

        name = 'radar'
        PolarTransform = RadarTransform

        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            # rotate plot such that the first axis is at the top
            self.set_theta_zero_location('N')

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

        def plot(self, *args, **kwargs):
            """Override plot so that line is closed by default"""
            lines = super().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.append(x, x[0])
                y = np.append(y, y[0])
                line.set_data(x, y)

        def set_varlabels(self, labels):
            self.set_thetagrids(np.degrees(theta), labels)

        def _gen_axes_patch(self):
            # The Axes patch must be centered at (0.5, 0.5) and of radius 0.5
            # in axes coordinates.
            if frame == 'circle':
                return Circle((0.5, 0.5), 0.5)
            elif frame == 'polygon':
                return RegularPolygon((0.5, 0.5), num_vars,
                                      radius=.5, edgecolor="k")
            else:
                raise ValueError("Unknown value for 'frame': %s" % frame)

        def _gen_axes_spines(self):
            if frame == 'circle':
                return super()._gen_axes_spines()
            elif frame == 'polygon':
                # spine_type must be 'left'/'right'/'top'/'bottom'/'circle'.
                spine = Spine(axes=self,
                              spine_type='circle',
                              path=Path.unit_regular_polygon(num_vars))
                # unit_regular_polygon gives a polygon of radius 1 centered at
                # (0, 0) but we want a polygon of radius 0.5 centered at (0.5,
                # 0.5) in axes coordinates.
                spine.set_transform(Affine2D().scale(.5).translate(.5, .5)
                                    + self.transAxes)
                return {'polar': spine}
            else:
                raise ValueError("Unknown value for 'frame': %s" % frame)

    register_projection(RadarAxes)
    return theta


def example_data():
    data = [
        ['WW yield', 'WR yield', 'WB yield', 'SM yield','N leached','Net N minerilization',
        'Emitted soil $N_{2}$O','Organic soil N','Organic soil C','Emitted soil $CO_{2}$'],
        ('WW-WR-WB-SM', [
            [0.629053747,0.254076315,0.332256277,0.204105265,0.133944624,0.318652711,0.075673605,0.207815416,0.268688223,
             0.355527198],
            [0.638266936,0.256631724,0.34185792,0.212581768,0.120456481,0.335636918,0.075777949,0.2048961,0.265332129,
             0.363333365],
            [0.6216949,0.261880304,0.373231106,0.458953575,0.099304806,0.389855072,0.060179553,0.376827867,0.411683333,
             0.4480729]]),
        ['WR yield', 'WB yield', 'WW yield', 'SP yield','N leached','Net N minerilization',
        'Emitted soil N$_{2}$O','Organic soil N','Organic soil C','Emitted soil $CO_{2}$'], **#here I have different label**
        ('WR-WB-WW-SP', [
            [0.303873044,0.343198048,0.72326815,0.470654888,0.147377613,0.349091327,0.087892159,0.215422083,0.273716559,
             0.357139508],
            [0.344731808,0.336010854,0.714918073,0.52981827,0.102251601,0.378815911,0.062455782,0.205903907,0.265096764,
             0.377555353],
            [0.329971424,0.380316019,0.809793741,0.59992031,0.110443314,0.457303888,0.08134116,0.413050845,0.435613362,
             0.472325334]])
    ]
    return data


if __name__ == '__main__':
    N = 10
    theta = radar_factory(N, frame='polygon')

    data = example_data()
    spoke_labels = data.pop(0)

    fig, axs = plt.subplots(figsize=(20, 20), nrows=2, ncols=1,
                            subplot_kw=dict(projection='radar'))

    labels = ('Factor 1', 'Factor 2', 'Factor 3')
    num_vars = len(labels)
    colors = ['b', 'r', 'g']
    # Plot the two cases from the example data on separate axes
    for ax, (title, case_data) in zip(axs.flat, data):
        #ax.set_rgrids([0.2, 0.4, 0.6, 0.8],angle=360)
        ax.set_title(title, weight='bold', size='medium', position=(0.5, 1.1),
                     horizontalalignment='center', verticalalignment='center')
        for d, color in zip(case_data, colors):
            ax.plot(theta, d,'--', color=color)
        ax.set_varlabels(spoke_labels)
        ax.set_rgrids([0,0.1, 0.2, 0.3, 0.4, 0.5,0.6,0.7,0.8],angle=90)
        ax.grid(color='silver',linestyle='-', linewidth=0.5,dash_capstyle='projecting',ds='default')
        ax.spines['polar'].set_visible(False)
        ax.set_rlabel_position(90 / num_vars)
        ax.legend(['Factor 1', 'Factor 2', 'Factor 3'],bbox_to_anchor=(1.1, 1.05),loc='best',frameon=False)

    

    plt.show()

This error is produced because of the zip(axs.flat, data) received too many values to unpack. How to resolve it? should the data be separated for each case and plotted on two axes. If this is the case, appreciate any relevant example...

[![~\AppData\Local\Temp\ipykernel_17292\4071153916.py in <module>
    157     colors = \['b', 'r', 'g'\]
    158     # Plot the four cases from the example data on separate axes
--> 159     for ax, (title, case_data) in zip(axs.flat, data):
    160         #ax.set_rgrids(\[0.2, 0.4, 0.6, 0.8\],angle=360)
    161         ax.set_title(title, weight='bold', size='medium', position=(0.5, 1.1),

ValueError: too many values to unpack (expected 2)][2]][2]

enter image description here

Ahmed Attia
  • 153
  • 1
  • 8
  • 1
    You have multiple labels. You removed 1 list of labels with `spoke_labels = data.pop(0)`, so just remove the other list of labels, which is not needed `data.pop(1)`. See [code and plot](https://i.stack.imgur.com/mFGkw.png) – Trenton McKinney May 19 '23 at 18:32

1 Answers1

0

In addition to the solution in the comment above, I did this way

fig, axes = plt.subplots(2,1,figsize=(9,9),subplot_kw=dict(projection='radar'),tight_layout=True) 
ax1, ax2 = axes.flatten() 
fig.subplots_adjust(wspace=0.20, hspace=0, top=1.2, bottom=0.05)

def add_to_radar(code, color,linestyle):
  values = dfR2CC.loc[code].tolist()
  ax1.plot(angles, values, color=color,linestyle=linestyle, linewidth=1, label=code)
  ax1.fill(angles, values, color=color, alpha=0.10, label='_nolegend_')

# Add each car to the chart.
add_to_radar(1, 'r','-')
#add_to_radar(2, '#000000')
add_to_radar(6, 'b','--')
#add_to_radar(5, '#0343DF')
add_to_radar(8, 'g','-.')
#add_to_radar(8, '#4B0082')
# Fix axis to go in the right order and start at 12 o'clock.
ax1.set_theta_offset(np.pi / 2)
ax1.set_theta_direction(-1)

# Draw axis lines for each angle and label.
ax1.set_thetagrids(np.degrees(angles), labels)

# Go through labels and adjust alignment based on where
# it is in the circle.
for label, angle in zip(ax1.get_xticklabels(), angles):
  if angle in (0, np.pi):
    label.set_horizontalalignment('center')
  elif 0 < angle < np.pi:
    label.set_horizontalalignment('left')
  else:
    label.set_horizontalalignment('right') 
    
ax1.legend(['WW–WR–WB–SM','WW–WR–LCC–WB–LCC–SM','WW–WR–NLCC–WB–LCC–SM'], fontsize=7, 
           bbox_to_anchor=(0.96,0.95),loc='upper right', bbox_transform=fig.transFigure)
ax1.set_varlabels(spoke_labels)
ax1.set_rgrids([0,0.1, 0.2, 0.3, 0.4, 0.5,0.6,0.7],angle=140,fontsize=6)
ax1.grid(color='silver',linestyle='-', linewidth=0.7,dash_capstyle='projecting',ds='steps-mid')
ax1.spines['polar'].set_visible(False)
ax1.set_rlabel_position(140 / num_vars)
ax1.set_title('WW-WR-WB-SM',weight='bold', size='medium', y=0.9,x=-0.3,
                     horizontalalignment='center', verticalalignment='center')

def add_to_radar(code, color,linestyle):
  values3 = dfR3CC.loc[code].tolist()
  ax2.plot(angles, values3, color=color,linestyle=linestyle, linewidth=1, label=code)
  ax2.fill(angles, values3, color=color, alpha=0.10, label='_nolegend_')

# Add each car to the chart.
add_to_radar(1, 'r','-')
#add_to_radar(2, '#000000')
add_to_radar(4, 'b','--')
#add_to_radar(5, '#0343DF')
add_to_radar(7, 'g','-.')
add_to_radar(9, 'darkgoldenrod',':')
# Fix axis to go in the right order and start at 12 o'clock.
ax2.set_theta_offset(np.pi / 2)
ax2.set_theta_direction(-1)

# Draw axis lines for each angle and label.
ax2.set_thetagrids(np.degrees(angles), labels3)

# Go through labels and adjust alignment based on where
# it is in the circle.
for label, angle in zip(ax2.get_xticklabels(), angles):
  if angle in (0, np.pi):
    label.set_horizontalalignment('center')
  elif 0 < angle < np.pi:
    label.set_horizontalalignment('left')
  else:
    label.set_horizontalalignment('right') 
    
ax2.legend(['WR–WB–WW–SB','WR–NLCC–WB–NLCC–WW–NLCC–SB',
            'WR–LCC–WB–LCC–WW–LCC–SB','WR–NLCC–WB–NLCC–WW–LCC–SB'],  fontsize=7,
            bbox_to_anchor=(0.96,0.45),loc='upper right', bbox_transform=fig.transFigure)
ax2.set_varlabels(spoke_labels3)
ax2.set_rgrids([0,0.1, 0.2, 0.3, 0.4, 0.5,0.6,0.7],angle=140,fontsize=6)
ax2.grid(color='silver',linestyle='-', linewidth=0.7,dash_capstyle='projecting',ds='steps-mid')
ax2.spines['polar'].set_visible(False)
ax2.set_rlabel_position(140 / num_vars)
ax2.set_title('WW-WR-WB-SB',weight='bold', size='medium', y=0.9,x=-0.3,
                     horizontalalignment='center', verticalalignment='center')
fig.tight_layout(pad=3)

plt.show()

enter image description here

Ahmed Attia
  • 153
  • 1
  • 8