Share @ LinkedIn Facebook  radar-chart, plotly
How to Plot Radar Charts in Python [plotly]?

How to Plot Radar Charts in Python [plotly]?

The radar chart is a technique to display multivariate data on the two-dimensional plot where three or more quantitative variables are represented by axes starting from the same point. The relative position and angle of lines are of no importance. Each observation is represented by a single point on all axes. All points representing each quantitative variable is connected in order to generate a polygon. All quantitative variables of data are scaled to the same level for comparison. We can look at the single observation of data to look at how each quantitative variable representing that samples are laid out on the chart.

The radar chart can be useful in identifying and comparing the behavior of observations. We can identify which observations are similar as well as outliers. The radar charts can be used at various places like sports to compare player performance, employee performance comparison, comparison of various programs based on different attributes, etc.

How to Plot Radar Charts in Python

The radar chart also commonly referred to as a web chart, spider chart, spider web chart, star chart, star plot, cobweb chart, polar chart, etc.

The radar charts also have a few limitations which are worth highlighting. If there are many observations to be displayed then radar charts get crowded. As more polygons are layered on top of each other, distinguishing observations becomes difficult. Each axis of the radar chart has the same scale which means that we need to scale data and bring all columns to the same scale. The alternative charts to avoid pitfalls of radar charts are parallel coordinate charts and bar charts.

The parallel coordinates chart is almost the same chart as radar chart except that it lays out quantitative variables in parallel vertically unlike radar chart which lays out them as radially. We have covered small a tutorial explaining the usage of parallel coordinates chart using python. Please feel free to explore it if you want to learn about how to plot a parallel coordinates chart in python.

This ends our small intro of radar charts. We'll now start with the coding part by importing necessary libraries.

In [1]:
import pandas as pd
import numpy as np

from sklearn.datasets import load_iris, load_wine
from sklearn.preprocessing import MinMaxScaler

We'll be first loading 2 datasets available from scikit-learn.

  • IRIS Flowers Dataset It has dimension measured for 3 different IRIS flower types.
  • Wine Dataset It has information about various ingredients of wine like alcohol, malic acid, ash, magnesium, etc for three different wine categories.

Both of these datasets are available from the sklearn.datasets module. We'll be loading them and keeping them as a dataframe for using them later for radar charts.

Radar chart expects those quantitative variables that we are going to plot are on the same scale. We have used scikit-learn MinMaxScaler scaler to scale data so that each column’s data gets into range [0-1]. Once data is into the same range [0-1] for all quantitative variables then it becomes easy to see its impact. We'll be scaling both iris and wine datasets using MinMaxScaler.

In [2]:
iris = load_iris()
iris_data = MinMaxScaler().fit_transform(iris.data)
iris_data = np.hstack((iris_data, iris.target.reshape(-1,1)))

iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names+ ["FlowerType"])
iris_df.head()
Out[2]:
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) FlowerType
0 0.222222 0.625000 0.067797 0.041667 0.0
1 0.166667 0.416667 0.067797 0.041667 0.0
2 0.111111 0.500000 0.050847 0.041667 0.0
3 0.083333 0.458333 0.084746 0.041667 0.0
4 0.194444 0.666667 0.067797 0.041667 0.0
In [3]:
wine = load_wine()
wine_data = MinMaxScaler().fit_transform(wine.data)
wine_data = np.hstack((wine_data, wine.target.reshape(-1,1)))

wine_df = pd.DataFrame(data=wine_data, columns=wine.feature_names+ ["WineCat"])
wine_df.head()
Out[3]:
alcohol malic_acid ash alcalinity_of_ash magnesium total_phenols flavanoids nonflavanoid_phenols proanthocyanins color_intensity hue od280/od315_of_diluted_wines proline WineCat
0 0.842105 0.191700 0.572193 0.257732 0.619565 0.627586 0.573840 0.283019 0.593060 0.372014 0.455285 0.970696 0.561341 0.0
1 0.571053 0.205534 0.417112 0.030928 0.326087 0.575862 0.510549 0.245283 0.274448 0.264505 0.463415 0.780220 0.550642 0.0
2 0.560526 0.320158 0.700535 0.412371 0.336957 0.627586 0.611814 0.320755 0.757098 0.375427 0.447154 0.695971 0.646933 0.0
3 0.878947 0.239130 0.609626 0.319588 0.467391 0.989655 0.664557 0.207547 0.558360 0.556314 0.308943 0.798535 0.857347 0.0
4 0.581579 0.365613 0.807487 0.536082 0.521739 0.627586 0.495781 0.490566 0.444795 0.259386 0.455285 0.608059 0.325963 0.0

We have grouped iris flowers dataset by flower type and have then take the mean of each column. This will give us the average value of each data dimension for each flower type. We'll use this data to plot radar charts.

In [4]:
avg_iris  = iris_df.groupby("FlowerType").mean()
avg_iris
Out[4]:
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm)
FlowerType
0.0 0.196111 0.595000 0.078305 0.060833
1.0 0.454444 0.320833 0.552542 0.510833
2.0 0.635556 0.405833 0.771525 0.802500

We have grouped the wine dataset by wine categories and have then taken the mean of each column. This will give us the average value of each data dimension for each wine category that we'll use to plot radar charts. We can take an individual samples and create a radar chart from it as well but here we'll be creating a radar chart of the average of each category so that we'll get an idea about each category as a whole.

In [5]:
avg_wine = wine_df.groupby("WineCat").mean()
avg_wine
Out[5]:
alcohol malic_acid ash alcalinity_of_ash magnesium total_phenols flavanoids nonflavanoid_phenols proanthocyanins color_intensity hue od280/od315_of_diluted_wines proline
WineCat
0.0 0.714407 0.251122 0.585879 0.331819 0.394989 0.641438 0.557463 0.301887 0.469818 0.362483 0.473198 0.691501 0.597512
1.0 0.328614 0.235707 0.473149 0.496806 0.266840 0.440991 0.367267 0.440872 0.384947 0.154148 0.468522 0.555074 0.172259
2.0 0.558882 0.512599 0.575980 0.557560 0.318614 0.240948 0.093135 0.599057 0.234556 0.521864 0.164804 0.151480 0.250996

Plotly provides two different methods for creating radar charts.

  • plotly.express.line_polar
  • plotly.graph_objects.Scatterpolar

We'll be explaining both one by one now.

Plotly Express

The plotly express module provides a method named line_polar() which can be used for creating a radar chart. It accepts dataframe as input and column name of dataframe which can be used for radar chart axis and axis values. It has two important parameters:

  • theta - It accepts string name representing column name of dataframe where the name of different quantitative variables is stored. It also accepts a list of string names representing quantitative variable names.
  • r - It accepts string name representing column name of dataframe where values about particular observation are present. It also accepts a list of values representing value for each quantitative variable passed to the theta parameter.

There are other attributes of data that are generic to plotly for plot decoration.

We'll be first plotting IRIS flower setosa based on average values we have calculated for this flower type.

In [6]:
import plotly.express as px
In [ ]:
fig = px.line_polar(
                    r=avg_iris.loc[0].values,
                    theta=avg_iris.columns,
                    line_close=True,
                    range_r = [0,1.0],
                    title="IRIS - %s"%iris.target_names[0])


fig.show()

How to Plot Radar Charts in Python

The line_close parameter if set to True will connect end variables to create the polygon. We have also set the range_r attribute to 0-1 because we scaled down all variables between 0-1 using MinMaxScaler earlier.

Below we are using same line_polar() function to plot radar chart for IRIS Versicolor flower type. We can also later update chart attributes by using the update_traces() method. We are filling radar chart polygon this time by setting fill attribute value to toself. We can also change the direction of quantitative variables layout by setting the direction attribute to counterclockwise. We can also set the start angle from where we want to start plotting quantitative variables by setting the start_angle attribute. The default for start_angle is 90.

In [ ]:
fig = px.line_polar(
                    r=avg_iris.loc[1].values,
                    theta=avg_iris.columns,
                    line_close=True,
                    range_r = [0,1.0],
                    title="IRIS - %s"%iris.target_names[1],
                    direction="counterclockwise", start_angle=45
                    )

fig.update_traces(fill='toself')
fig.show()

How to Plot Radar Charts in Python

Below we have plotted the radar chart for Wine of class 0. The wine dataset has 13 variables to compare.

In [ ]:
fig = px.line_polar(
                    r=avg_wine.loc[0].values,
                    theta=avg_wine.columns,
                    line_close=True,
                    range_r = [0,1.0],
                    title="WINE - %s"%wine.target_names[0]
                    )

fig.update_traces(fill='toself')
fig.show()

How to Plot Radar Charts in Python

In [ ]:
fig = px.line_polar(
                    r=avg_wine.loc[1].values,
                    theta=avg_wine.columns,
                    line_close=True,
                    title="WINE - %s"%wine.target_names[1],
                    range_r = [0,1.0]
                    )

fig.update_traces(fill='toself')
fig.show()

How to Plot Radar Charts in Python

We can see from the above two figures that alcohol is more in wine category 0 compared to wine category 1. The ash is also more in wine category 0 compared to wine category 1. We can compare all different quantitative variables this way.

Plotly Graph Objects

The second method provided by plotly is Scatterpolar available as a part of the graph_objects module of plotly. It has almost the same parameter requirement as that of line_polar() for creating radar charts. It expects that we provide parameter r and theta for generating radar charts. We can specify fill color, line color, fill, etc attributes by passing them directly to this method.

Below we are using Scatterpolar to generate radar chart for IRIS flower type verginica.

In [ ]:
import plotly.graph_objects as go

fig = go.Figure()
fig.add_trace(
                go.Scatterpolar(
                                r=avg_iris.loc[2].values,
                                theta=avg_iris.columns,
                                fill='toself',
                                name="IRIS-%s"%iris.target_names[2],
                                fillcolor="orange", opacity=0.6, line=dict(color="orange")
                                )
                )

fig.update_layout(
    polar=dict(
        radialaxis=dict(
          visible=True
        ),
      ),
    showlegend=False,
    title="IRIS-%s"%iris.target_names[2]
)

fig.show()

How to Plot Radar Charts in Python

We are now combining polygon for all 3 different iris flower types in a single radar chart. We are not filling color in the radar chart. We also have repeated first value 2 times in our logic in order to join ends of polygons of a radar chart.

In [ ]:
fig = go.Figure()

for i in range(3):
    fig.add_trace(
                go.Scatterpolar(
                                r=avg_iris.loc[i].values.tolist() + avg_iris.loc[i].values.tolist()[:1],
                                theta=avg_iris.columns.tolist() + avg_iris.columns.tolist()[:1],
                                name="IRIS-%s"%iris.target_names[i],
                                showlegend=True,
                                )
                )

fig.update_layout(
    polar=dict(
        radialaxis=dict(
                        visible=True,
                        range=[0, 1]
                    )
            ),

    title="IRIS Flower Variables According to Flower Categories"
)

fig.show()

How to Plot Radar Charts in Python

We can easily compare quantitative variables of different flower types easily now. We can see that iris setosa has on an average more sepal width compared to the other two. Iris versicolor is smaller in size compared to iris virginica. Iris virginica has the biggest petal length, petal width, and sepal length compared to the other two.

Below we are again plotting three different iris flowers with their polygon filled in this time.

In [ ]:
fig = go.Figure()

colors= ["tomato", "dodgerblue", "yellow"]
for i in range(3):
    fig.add_trace(
                go.Scatterpolar(
                                r=avg_iris.loc[i].values.tolist() + avg_iris.loc[i].values.tolist()[:1],
                                theta=avg_iris.columns.tolist() + avg_iris.columns.tolist()[:1],
                                fill='toself',
                                name="IRIS-%s"%iris.target_names[i],
                                fillcolor=colors[i], line=dict(color=colors[i]),
                                showlegend=True, opacity=0.6
                                )
                )

fig.update_layout(
    polar=dict(
        radialaxis=dict(
                        visible=True,
                        range=[0, 1]
                    )
            ),
    title="IRIS Flower Variables According to Flower Categories"
)

fig.show()

How to Plot Radar Charts in Python

Below we are plotting three different wine types on a single radar chart. We can easily compare different quantitative variables across different wine types now.

In [ ]:
fig = go.Figure()

for i in range(3):
    fig.add_trace(
                go.Scatterpolar(
                                r=avg_wine.loc[i].values,
                                theta=avg_wine.columns,
                                fill='toself',
                                name="WINE-%s"%wine.target_names[i],
                                showlegend=True,
                                )
                )

fig.update_layout(
    polar=dict(
        radialaxis=dict(
                        visible=True,
                        range=[0, 1]
                    )
            ),
    title="Wine Variables According to Wine Categories"
)

fig.show()

How to Plot Radar Charts in Python

We can notice from the above chart that wine class 0 has the highest amount of alcohol. Wine class 0 also has more proline, magnesium, phenols, flavonoids, proanthocyanins, and od280/od315 compared to the other two wine types. Wine class 2 has more malic acid, the alkalinity of ash, non-flavonoid phenols, and color intensity compared to the other two wine types.

This ends our small tutorials explaining radar charts plotting using python. Please feel free to let us know your views in the comments section.

References



Sunny Solanki  Sunny Solanki