Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Radar chart feature for visualizing geodemographic classifications #49

Open
SamComber opened this issue Mar 13, 2019 · 6 comments
Open
Labels
enhancement wishlist Functionality that should be supported in future

Comments

@SamComber
Copy link

Having recently worked on a paper that visualizes the findings of a geodemographic classification (w/ @darribas), we were wondering if there might be appetite for introducing a radar chart to the plotting library for displaying multivariate variation across the resulting cluster partitions.

AFAIK there is no quick and easy mapping library offering this functionality, so if there is interest in introducing this feature I would be happy to contribute the code I have been using for the working paper.

@knaaptime
Copy link
Member

it would definitely be of interest to osnap, but might be better implemented here. Do you have other ideas about useful visualizations for geodemographic-style work? We have @slumnitz joining us for the next few months, so it would be great to capture ideas for other viz we could build into splot that support these analyses

@darribas
Copy link
Member

My vote would probably go to have it here and then use it as needed in osnap, as splot is designed to support a more general range of applications. Having said that, osnap is focused on neighborhoods so, to the extent radar charts are mostly used in that context, that might also make sense.

@slumnitz, do you think this could be contributed to splot in a way that is more general than "just" for neighborhood analysis? I'd think so, as arguably in some regionalisations this would be useful too?

@knaaptime
Copy link
Member

sounds like we're of one mind... if it's implemented here, it would be available to a wider set of use cases and osnap could just consume it. osnap might be the primary consumer for awhile until we figure out how broadly applicable this particular viz is, but that seems like the strategy i'd vote for too

@slumnitz
Copy link
Member

Yeah I think all your suggestions make sense! We could create a function api that allows quite generic input here in splot under a specific splot.? namespace (splot.cluster, splot.point, splot.utils, splot.model ... we can have a think about where else radar plots would be helpful) and then additionally expose the functionality as .plot() functionality tailored to osnap in osnap. This would only add a splot dependency to osnap if that is ok with @knaaptime?

@SamComber code contributions are always super helpful and welcome! :) We could also think about exposing you project with the splot radar plot as a notebook if you are interested?

@slumnitz slumnitz added enhancement wishlist Functionality that should be supported in future labels Mar 14, 2019
@slumnitz
Copy link
Member

slumnitz commented Apr 8, 2020

Hi @SamComber would you still be interested in integrating this feature into splot? I am happy to help. Do you have a link to the code to have a look? Also do you have an example viz, that might also help in deciding where this should go. Hope all is well!

@SamComber
Copy link
Author

Hi @slumnitz, unfortunately I'm quite tied up finishing off my PhD and internship (concurrently) at the moment, so my time is quite limited for the next two months or so. Here's a code snippet that creates a similar visualisation to what I used in the paper, albeit with some toy data. The code is pretty simple, so I'll paste it below, but I guess a lot more work would be needed to make it robust!

I think this would be a really useful feature for summarising geodemographics or even clustering exercises in general, as I struggled to find anything for creating these kind of charts.

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

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

    categories=list(radar_dfs)
    N = len(categories)
    
    # generate slices 
    angles = np.arange(N+1)/N*2*np.pi
    values = radar_dfs.iloc[row].values.flatten().tolist()
    values += values[:1]
    
    # plot radar surface
    ax.plot(angles, values, color=color,linewidth=2, linestyle='solid')
    ax.fill(angles, values, color=color, alpha=0.4)
    
    # change position of number legend
#     ax.set_theta_offset(math.pi / 2)
#     ax.set_theta_direction(-1)
    
    # change label and tick params
    ax.set_xticks(angles[:-1])
    ax.set_xticklabels(categories, color='grey', size=16)
    ax.tick_params(labelleft=True, pad=10)
    
    ax.set_title(title, pad=20, color=color, size=24)

radar_dfs = pd.DataFrame.from_dict({"v1":{"0":-0.3470532925,"1":-0.082144001,"2":-0.082144001,"3":-0.3470532925,"4":-0.3470532925},
                                    "v2":{"0":-0.1858487321,"1":-0.1685491141,"2":-0.1632483955,"3":-0.1769700284,"4":-0.0389887094},
                                    "v3":{"0":-0.073703681,"1":-0.073703681,"2":-0.073703681,"3":-0.073703681,"4":-0.073703681},
                                    "v4":{"0":-0.2416123064,"1":-0.2841806825,"2":-0.259622004,"3":-0.3529449824,"4":-0.3414842657},
                                    "v5":{"0":-0.1271390651,"1":-0.3105853643,"2":-0.2316607937,"3":-0.3297832328,"4":-0.4599021194},
                                    "v6":{"0":-0.1662745006,"1":-0.1426329043,"2":-0.1577528867,"3":-0.163560133,"4":-0.1099718326},
                                    "v7":{"0":-0.0251535462,"1":-0.1540641646,"2":-0.0204666924,"3":-0.0515740013,"4":-0.0445135996},
                                    "v8":{"0":-0.0826103951,"1":-0.1777759951,"2":-0.114263357,"3":-0.1787044751,"4":-0.2709496389},
                                    "v9":{"0":-0.105481688,"1":-0.1760349683,"2":-0.128215043,"3":-0.1560577648,"4":-0.1760349683}})

palette =['#79BD9A','#69D2E7','#F38630', '#547980','#EDC951']
labels = ['A', 'B', 'C', 'D', 'E']

# 2x1x2 layout
fig = plt.figure(figsize=(20,16))
position = [[0,0], [2,0], [1,1], [0,2], [2,2]]

axes = []
for row, (letter, col) in enumerate(zip(labels, palette)):
    ax = plt.subplot2grid([4,3], position[row], rowspan=2, colspan=1, **{'polar': True}, sharey=axes[0] if row else None)
    axes.append(ax)
    spider_plot( row  = row, title='Group ' + str(letter), color=col, ax=ax)

plt.subplots_adjust(wspace=.4, hspace=.3)
plt.show()

example_viz_clusters

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement wishlist Functionality that should be supported in future
Projects
None yet
Development

No branches or pull requests

4 participants