How to add values at the end of Radar Chart points? - python

so I am plotting a Radar Chart and I need to add values at the end of each point of the chart. Is there a way? Main area of code and df enlisted below.
"""PLOT GRAPH 1"""
categories=list(df)[0:]
N = len(categories)
categories=list(df)[0:]
N = len(categories)
values=df.iloc[1].values.flatten().tolist()
values += values[:1]
for_tick=df.iloc[0].values.flatten().tolist()
for_tick += for_tick[:1]
angles = [n / float(N) * 2 * pi for n in range(N)]
angles += angles[:1]
f, ax = plt.subplots(1,1,figsize=(8,6))
ax = plt.subplot(111, polar=True)
plt.xticks(angles[:-1], wrapped_labels , size=10)
ax.set_rlabel_position(0)
plt.yticks([0,25,50,75,100], color="grey", size=5)
plt.ylim(0,100)
plt.title('Suppliers hit in the test out of all supliers (' +number_of_suppliers+') (in %)')
ax.plot(angles, values, color='#ffe600', linewidth=1, linestyle='solid')
ax.fill(angles, values, color='#ffe600', alpha=0.3)
plt.savefig(r'C:\Radar\firmy.png',dpi=100)
plt.show()

So I managed to find a more manual way, as there were only five values to label, of how to do it, adding this line of code. If I find more intuitive and automatic way, I will update you :)
ax.annotate(labels[0], xy=(angles[0],values[0]), textcoords='data',size=5,ha="center", va="center")
ax.annotate(labels[1], xy=(angles[1],values[1]), textcoords='data',size=5,ha="center", va="center")
ax.annotate(labels[2], xy=(angles[2],values[2]), textcoords='data',size=5,ha="center", va="center")
ax.annotate(labels[3], xy=(angles[3],values[3]), textcoords='data',size=5,ha="center", va="center")
ax.annotate(labels[4], xy=(angles[4],values[4]), textcoords='data',size=5,ha="center", va="center")

Related

Graph with loop which does not display in streamlit

i try to do a spyder graph for my streamlit app. However, it functions on my notebook but not in my streamlit. Is anyone has an idea of the problem it does not display anything ?
Spider_kmeans = df[['Cluster_kmeans_Label','Age','Annual Income (k$)','Spending Score (1-100)','Sex (100=Male)']]
Spider_kmeans = Spider_kmeans.groupby('Cluster_kmeans_Label')['Cluster_kmeans_Label','Age','Annual Income (k$)','Spending Score (1-100)','Sex (100=Male)'].mean().reset_index()
def make_spider_kmeans( row, title, color):
# number of variable
categories=list(Spider_kmeans)[1:]
N = len(categories)
# What will be the angle of each axis in the plot? (we divide the plot / number of variable)
angles = [n / float(N) * 2 * pi for n in range(N)]
angles += angles[:1]
# Initialise the spider plot
ax = plt.subplot(3,3,row+1, polar=True)
# If you want the first axis to be on top:
ax.set_theta_offset(pi / 2)
ax.set_theta_direction(-1)
# Draw one axe per variable + add labels labels yet
plt.xticks(angles[:-1], categories, color='black',fontfamily='serif',fontweight='light', size=8)
#ax.set_xticks([]) # turn labels off if you want - can look quite nice
# Draw ylabels
ax.set_rlabel_position(0)
plt.yticks([10,20,30,40,50,75,100], ["10","20","30","40","50","75","100"], color="grey", size=4)
plt.ylim(0,100)
# Ind1
values= Spider_kmeans.loc[row].drop('Cluster_kmeans_Label').values.flatten().tolist()
values += values[:1]
ax.plot(angles, values, color=color, linewidth=2, linestyle='solid')
ax.fill(angles, values, color=color, alpha=0.4)
# Add a title
plt.title(title, size=10, fontfamily='serif',fontweight='bold', y=1.2)
plt.tight_layout()
#############################################################################################
my_dpi=96
plt.figure(figsize=(1000/my_dpi, 1000/my_dpi), dpi=my_dpi)
# Create a color palette:
my_palette = plt.cm.get_cmap("crest", len(df.index))
then i put this code on my streamlit app
for row in range(0, len(Spider_kmeans.index)):
make_spider_kmeans( row=row, title='Cluster: '+ Spider_kmeans['Cluster_kmeans_Label'][row], color='#244747') #change this to my_palette if you want colour to vary by cluster
I

3D Plot of Multiple Time Series in Python

I've seen numerous examples of 3D plots using matplotlib/seaborn in Python but can't seem to get what I'm looking for; I have 50 or so timeseries that I would like to plot cleanly as in the following example below but with the name of the series on the axis; as an example I've marked in Goog, IBM, GE, Pepsi etc. Appreciate any pointers or examples. Thank you,
Example PLOT Click Here Please
Matplotlib has very rich gallery. I found this, you can only plot it once instead of animation. And manually put y-axis legend wherever you want.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# Fixing random state for reproducibility
np.random.seed(19680801)
# Create new Figure with black background
fig = plt.figure(figsize=(12, 8))
# Add a subplot with no frame
ax = plt.subplot(111, frameon=False)
# Generate random data
data = np.random.uniform(0, 1, (64, 75))
X = np.linspace(-1, 1, data.shape[-1])
G = 1.5 * np.exp(-4 * X ** 2)
# Generate line plots
lines = []
for i in range(len(data)):
# Small reduction of the X extents to get a cheap perspective effect
xscale = 1 - i / 200.
# Same for linewidth (thicker strokes on bottom)
lw = 1.5 - i / 100.0
line, = ax.plot(xscale * X, i + G * data[i], color="b", lw=lw)
lines.append(line)
# Set y limit (or first line is cropped because of thickness)
ax.set_ylim(-1, 70)
# No ticks
ax.set_xticks([])
ax.set_yticks([])
# 2 part titles to get different font weights
ax.text(0.5, 1.0, "MATPLOTLIB ", transform=ax.transAxes,
ha="right", va="bottom", color="k",
family="sans-serif", fontweight="light", fontsize=16)
ax.text(0.5, 1.0, "UNCHAINED", transform=ax.transAxes,
ha="left", va="bottom", color="k",
family="sans-serif", fontweight="bold", fontsize=16)
def update(*args):
# Shift all data to the right
data[:, 1:] = data[:, :-1]
# Fill-in new values
data[:, 0] = np.random.uniform(0, 1, len(data))
# Update data
for i in range(len(data)):
lines[i].set_ydata(i + G * data[i])
# Return modified artists
return lines
# Construct the animation, using the update function as the animation director.
anim = animation.FuncAnimation(fig, update, interval=10)
plt.show()

Plotting energy levels in stacks, on top of one another

I have a code that gives me different energy levels. The code and the output is shown here:
from numpy import*
from matplotlib.pyplot import*
N=[0,1,2,3,4]
s=0.5
hw=1
def Energy(n):
if n%2==0:
if n==0:
j=0.5
E=[(n+1.5)*hw-0.1*(j-0.5)*0.5-0.0225*(j+0.5)*(j-0.5)]
return(E)
else:
l=list(range(0,n+2,2))
j1=[abs(l+s) for l in l ]
j2=[l-s for l in l]
j2=list(filter(lambda x:x>0,j2))
E1=[(n+1.5)*hw-0.1*(j-0.5)*0.5-0.0225*(j+0.5)*(j-0.5) for j in j1]
E2=[(n+1.5)*hw+0.1*(j+0.5)*0.5-0.0225*(j+0.5)*(j-0.5) for j in j2]
return(E1+E2)
else:
l=list(range(1,n+2,2))
j1=[abs(l+s) for l in l]
j2=[abs(l-s) for l in l]
E1=[(n+1.5)*hw-0.1*(j-0.5)*0.5-0.0225*(j+0.5)*(j-0.5) for j in j1]
E2=[(n+1.5)*hw+0.1*(j+0.5)*0.5-0.0225*(j+0.5)*(j-0.5) for j in j2]
return(E1+E2)
E=[]
for n in N:
E.extend(Energy(n))
E.sort()
print(E)
orbital=[r'$1s_{1/2}$',r'$1p_{3/2}$',r'$1p_{1/2}$',r'$1d_{5/2}$',r'$2s_{1/2}$',r'$1d_{3/2}$',r'$1f_{7/2}$',r'$2p_{3/2}$',r'$1f_{5/2}$',r'$2p_{1/2}$',r'$1g_{9/2}$',r'$2d_{5/2}$',r'$1g_{7/2}$',r'$3s_{1/2}$',r'$2d_{3/2}$']
x = arange(len(E))
fig, ax =subplots()
ax.scatter(x, E, s=900, marker="_", linewidth=2, zorder=3)
ax.grid(axis='y')
for xi,yi,tx in zip(x,E,orbital):
ax.annotate(tx, xy=(xi,yi), xytext=(7,-3), size=5,
ha="center",va='top', textcoords="offset points")
ax.margins(0.1)
ylabel('energy >>')
title('Nuclear Energy levels')
The output is a graph containing the energy levels but spread out parallel to the x axis
What I actually need is the levels to not be spread across. I want them in a stack, one on the top of another. I tried modifying this code for that, but to no avail. Can someone help with this?
Instead of
x = arange(len(E))
(just before fig, ax =subplots()) use
x = [1] * len(E)
to have the same x-coordinate for all your levels:
You will probably want to increase the parameter s=, too, in your ax.scatter() method, for example to 90000:
ax.scatter(x, E, s=90000, marker="_", linewidth=2, zorder=3)
and change position of annotations — slightly change parameters xy=, xytext= in your code
for xi,yi,tx in zip(x,E,orbital):
ax.annotate(tx, xy=(xi,yi), xytext=(7,-3), size=5,
ha="center",va='top', textcoords="offset points")
to (for example):
for xi, yi, tx in zip(x, E, orbital):
ax.annotate(tx, xy=(.65*xi, yi), xytext=(7, 3), size=5,
ha="center", va='top', textcoords="offset points")
and change the overall image size to increase gaps between levels — in your
fig, ax = subplots()
use the figsize= parameter:
fig, ax = subplots(figsize=(6.5, 12))
Finally, you may remove ticks from x-axis and add minor ticks to y-axis:
import matplotlib as mpl # this line is better to put near the start of your code
ax.set_xticks([])
ax.yaxis.set_minor_locator(mpl.ticker.MaxNLocator(50))

How to colour circular lines in polar chart (matplotlib)

I'm trying to to colour the circular line that corresponds to the value of 0 in a polar chart. This is what I want to achieve:
On this related question (Shading a segment between two lines on polar axis (matplotlib)), ax.fill_between is used to fill the space between two values, but I'm looking for a way to colour just the circular line where the value for each variable is 0.
If anybody has any tips that would be most appreciated! I've inserted a minimal working example below if anybody fancies having a go.
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(.4)
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) )
Example dataframe here:
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}})
Probably a cheap hack based on the link you shared. The trick here is to simply use 360 degrees for fill_between and then use a very thin region around the circular line for 0 using margins such as -0.005 to 0.005. This way, you make sure the curve is centered around the 0 line. To make the line thicker/thinner you can increase/decrease this number. This can be straightforwardly extended to color all circular lines by putting it in a for loop.
ax.plot(angles, values, color=color, linewidth=2, linestyle='solid')
ax.fill(angles, values, color=color, alpha = .4)
ax.fill_between(np.linspace(0, 2*np.pi, 100), -0.005, 0.005, color='red', zorder=10) # <-- Added here
Other alternative could be to use a Circle patch as following
circle = plt.Circle((0, 0), 0.36, transform=ax.transData._b, fill=False, edgecolor='red', linewidth=2, zorder=10)
plt.gca().add_artist(circle)
but here I had to manually put 0.36 as the radius of the circle by playing around so as to put it exactly at the circular line for 0. If you know exactly the distance from the origin (center of the polar plot), you can put that number for exact position. At least for this case, 0.36 seems to be a good guess.
There is an easier option:
fig_radar.add_trace(go.Scatterpolar(
r = np.repeat(0, 360),
dtheta = 360,
mode = 'lines',
name = 'cirlce',
line_color = 'black',
line_shape="spline"
)
The addition of line_shape = "spline" makes it appear as a circle
dtheta divides the coordinates in so many parts (at least I understood it this way and it works)

scatter plot does not plot all the points in the array + ternary library

I am using the ternary library in python and trying to plot a scatter of points in the ternary plot.
However it appears the below code only plots one single point for each of the 3 scatter calls made.
Can you please advise
scale = 1
figure, tax = ternary.figure(scale=scale)
tax.set_title("Scatter Plot", fontsize=20)
tax.boundary(linewidth=2.0)
tax.gridlines(multiple=5, color="blue")
# Plot a few different styles with a legend
points = np.array([df['73_prop']])
tax.scatter(points, marker='s', color='red', label="Outflows")
points = np.array([df['72_prop']])
tax.scatter(points, marker='D', color='green', label="HQLA")
points = np.array([df['74_prop']])
tax.scatter(points, marker='o', color='blue', label="Inflows")
tax.legend()
tax.ticks(axis='lbr', linewidth=1, multiple=5)
tax.show()
Here is the plot i get right now
In [213]:points
Out[213]:
array([[ 0.47426346, 0.50559869, 0.50368877, ..., 0.65636812,
0.56024801, 0.49020411]])
P.S. Am trying to mimic what's there on:
https://github.com/marcharper/python-ternary#scatter-plots
I have also tried using certain for loop but hasn't helped.
Your input data has the wrong format. You supply a list of flots, you need to supply a list of list of floats: [ [x1,y1] , [x2,y2], ...]
This works:
import ternary
import numpy as np
scale = 1
figure, tax = ternary.figure(scale=scale)
tax.set_title("Scatter Plot", fontsize=20)
tax.boundary(linewidth=2.0)
tax.gridlines(multiple=5, color="blue")
rnd = np.random.random(120)
points = [ [x*x, np.random.random(1) * np.random.random(1) * (1-x)] for x in rnd]
tax.scatter(points, marker='s', color='red', label="Outflows")
rnd = np.random.random(120)
# [[x1,y1], [x2,y2], ..., [xn,yn]]
points = [ [x*x, np.random.random(1) * np.random.random(1) * (1-x)] for x in rnd]
tax.scatter(points, marker='D', color='green', label="HQLA")
rnd = np.random.random(120)
points = [ [x*x, np.random.random(1) * np.random.random(1) * (1-x)] for x in rnd]
tax.scatter(points, marker='o', color='blue', label="Inflows")
tax.legend()
tax.ticks(axis='lbr', linewidth=1, multiple=5)
tax.show()

Categories