2

I'm trying to make my subplots share the same axis, as they're currently different (it appears the circles in the plot itself are not perfectly aligned). When I try to pass sharex=True into ax = plt.subplot(1, 5, row+1, polar=True, sharex=True) I return an error suggesting TypeError: cannot create weak reference to 'bool' object.

Here is what my plot currently looks like, as you should be able to see, the axis (circles) inside the plot are not perfectly aligned, and I cannot work out how to align them using plt.subplot.

Does anybody have any recommendations?

enter image description here

Code to reproduce example:

import matplotlib.pyplot as plt
import pandas as pd    

def make_spider(row, title, color):

    import math

    categories = list(df)
    N = len(categories)

    angles = [n / float(N) * 2 * math.pi for n in range(N)]
    angles += angles[:1]

    ax = plt.subplot(1, 5, row+1, polar=True)

    plt.xticks(angles[:-1], categories, color='grey', size=8)

    values = df.iloc[row].values.flatten().tolist()
    values += values[:1]

    ax.plot(angles, values, color=color, linewidth=2, linestyle='solid')
    ax.fill(angles, values, color=color, alpha = .4)

    plt.gca().set_rmax(.2)


my_dpi = 40

plt.figure(figsize=(1000/my_dpi, 1000/my_dpi), dpi=96)

my_palette = plt.cm.get_cmap('Set2', len(df.index)+1)


for row in range(0, len(df.index)):
     make_spider( row  = row, title='Cluster: ' + str(row), color=my_palette(row) )

Dataframe:

df = pd.DataFrame.from_dict({"no_rooms":{"0":-0.3470532925,"1":-0.082144001,"2":-0.082144001,"3":-0.3470532925,"4":-0.3470532925},"total_area":{"0":-0.1858487321,"1":-0.1685491141,"2":-0.1632483955,"3":-0.1769700284,"4":-0.0389887094},"car_park_spaces":{"0":-0.073703681,"1":-0.073703681,"2":-0.073703681,"3":-0.073703681,"4":-0.073703681},"house_price":{"0":-0.2416123064,"1":-0.2841806825,"2":-0.259622004,"3":-0.3529449824,"4":-0.3414842657},"pop_density":{"0":-0.1271390651,"1":-0.3105853643,"2":-0.2316607937,"3":-0.3297832328,"4":-0.4599021194},"business_rate":{"0":-0.1662745006,"1":-0.1426329043,"2":-0.1577528867,"3":-0.163560133,"4":-0.1099718326},"noqual_pc":{"0":-0.0251535462,"1":-0.1540641646,"2":-0.0204666924,"3":-0.0515740013,"4":-0.0445135996},"level4qual_pc":{"0":-0.0826103951,"1":-0.1777759951,"2":-0.114263357,"3":-0.1787044751,"4":-0.2709496389},"badhealth_pc":{"0":-0.105481688,"1":-0.1760349683,"2":-0.128215043,"3":-0.1560577648,"4":-0.1760349683}})
2
  • By "the circles are not perfectly aligned", do you mean that you would like to have the grey circles at the exact same levels (i.e radius) for every polar plot in your figure ? Commented Jan 29, 2019 at 14:10
  • @Liris Yes, apologies for not being more explicit. Commented Jan 29, 2019 at 15:14

2 Answers 2

3

Best create the sharing a priori to plotting. The plot to the already shared axes.

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

dic = {"no_rooms":{"0":-0.347,"1":-0.082,"2":-0.082, "3":-0.347,"4":-0.347},
       "total_area":{"0":-0.185,"1":-0.168,"2":-0.163, "3":-0.176,"4":-0.038},
       "car_park_spaces":{"0":-0.073,"1":-0.073,"2":-0.073, "3":-0.073,"4":-0.073},
       "house_price":{"0":-0.241,"1":-0.284,"2":-0.259,"3":-0.352,"4":-0.341},
       "pop_density":{"0":-0.127,"1":-0.310,"2":-0.231,"3":-0.329,"4":-0.459},
       "business_rate":{"0":-0.166,"1":-0.142,"2":-0.157,"3":-0.163,"4":-0.109},
       "noqual_pc":{"0":-0.025,"1":-0.15,"2":-0.020,"3":-0.051,"4":-0.044},
       "level4qual_pc":{"0":-0.082,"1":-0.17,"2":-0.114,"3":-0.178,"4":-0.270},
       "badhealth_pc":{"0":-0.105,"1":-0.176,"2":-0.128,"3":-0.156,"4":-0.176}}
df = pd.DataFrame.from_dict(dic)


def make_spider(row, title, color, ax=None):

    categories = list(df)
    N = len(categories)
    angles = np.arange(N+1)/N*2*np.pi

    ax.set_xticks(angles[:-1])
    ax.set_xticklabels(categories, color='grey', size=8)
    ax.tick_params(labelleft=True)

    values = df.iloc[row].values.flatten().tolist()
    values += values[:1]

    ax.plot(angles, values, color=color, linewidth=2, linestyle='solid')
    ax.fill(angles, values, color=color, alpha = .4)


fig, axes = plt.subplots(ncols=len(df.index), subplot_kw=dict(polar=True), sharey=True,
                         figsize=(15,8))

my_palette = plt.cm.get_cmap('Set2', len(df.index)+1)


for row, ax in enumerate(axes):
     make_spider( row  = row, title='Cluster: ' + str(row), color=my_palette(row), ax=ax )

plt.show()

enter image description here

Sign up to request clarification or add additional context in comments.

3 Comments

Changing the rlim also results in unfilled plots: axes[0].set_rlim(-.3, .2). Any idea?
@Scotty1- Well, in case of rlim=(-.3, .2) one corner of the fill-polygon would be outside of the visible range. Hence no continuous filled region can be established. But I would suppose that you always want to show the complete polygon anyways, so that problem shouldn't occur.
You are right. Didn't consider the point that interpolation in polar coordinates is impossible towards lower limits if the values to plot are outside of the limits range...
2

You have to set the same y_lim/r_lim and y_ticks/r_ticks to all axes. This can for example be done by passing the last ax reference to plt.subplot to set sharey for all axes:

def make_spider(row, title, color, last_ax=None):    
    import math    
    categories = list(df)
    N = len(categories)    
    angles = [n / float(N) * 2 * math.pi for n in range(N)]
    angles += angles[:1]    
    # add last ax as sharey here:
    ax = plt.subplot(1, 5, row+1, polar=True, sharey=last_ax)    
    plt.xticks(angles[:-1], categories, color='grey', size=8)    
    values = df.iloc[row].values.flatten().tolist()
    values += values[:1]    
    ax.plot(angles, values, color=color, linewidth=2, linestyle='solid')
    ax.fill(angles, values, color=color, alpha = .4)    
    plt.gca().set_rmax(.2)

    # return axes to store them
    return plt.gca()  


my_dpi = 40    
plt.figure(figsize=(1000/my_dpi, 1000/my_dpi), dpi=96)    
my_palette = plt.cm.get_cmap('Set2', len(df.index)+1)    

axs = []  # store axes
for row in range(0, len(df.index)):
    if row != 0:  # if not the first subplot, pass last ax as argument
        axs.append(
            make_spider(row=row, title='Cluster: ' + str(row), color=my_palette(row), 
            last_ax=axs[row - 1]))
    else:
        axs.append(
            make_spider(row=row, title='Cluster: ' + str(row), color=my_palette(row)))

OR by passing the limits/ticks to the plots directly:

def make_spider(row, title, color, rlim, rticks):    
    import math    
    categories = list(df)
    N = len(categories)    
    angles = [n / float(N) * 2 * math.pi for n in range(N)]
    angles += angles[:1]

    ax = plt.subplot(1, 5, row+1, polar=True)    
    plt.xticks(angles[:-1], categories, color='grey', size=8)    
    values = df.iloc[row].values.flatten().tolist()
    values += values[:1]    
    ax.plot(angles, values, color=color, linewidth=2, linestyle='solid')
    ax.fill(angles, values, color=color, alpha = .4)    
    ax.set_rlim(rlim)
    ax.set_rticks(rticks)
    # return axes to store them (not needed but may help later)
    return ax

my_dpi = 40    
plt.figure(figsize=(1000/my_dpi, 1000/my_dpi), dpi=96)    
my_palette = plt.cm.get_cmap('Set2', len(df.index)+1)    

axs = []
for row in range(0, len(df.index)):
    axs.append(
        make_spider(
            row=row, title='Cluster: ' + str(row), color=my_palette(row), 
            rlim=(-.5, 0), rticks=[-.3, -.2, -.1, 0.]))

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.