Python Plotly Radar Chart with Style - python

I'm trying to the image shown below and I thought python would be a good idea to do this but I'm not sure. I want to randomize lots of football players' stats, make a radar chart for each and save the charts as images.
But the plotly radar charts are not so stylish and I really want to make something stylish. How to turn the below demo code into the reference image and is it possible?
Here's a demo code:
import plotly.graph_objects as go
categories = ['Defending','Speed','Attacking',
'Technical', 'Team play']
fig = go.Figure()
fig.add_trace(go.Scatterpolar(
r=[1, 5, 2, 2, 3],
theta=categories,
fill='toself',
name='Alice'
))
fig.add_trace(go.Scatterpolar(
r=[4, 3, 2.5, 1, 2],
theta=categories,
fill='toself',
name='Bob'
))
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=True,
range=[0, 5]
)),
showlegend=False
)
fig.show()

From the documentation for polar layout, it seems that Plotly does not offer much options when it comes the grid shape itself. However, Plotly allows you to create your own templates/themes or examine built-in themes.
As a starting point, you should probably analyze the plotly_dark theme as it has some features similar to your picture.
simple example with built-in template
dataset.csv
categories,player,points
Defending,alice,1
Speed,alice,5
Attacking,alice,2
Technical,alice,2
Team play,alice,3
Defending,bob,4
Speed,bob,3
Attacking,bob,2.5
Technical,bob,1
Team play,bob,2
code
import plotly.express as px
import pandas as pd
df = pd.read_csv("dataset.csv")
fig = px.line_polar(df, r="points",
theta="categories",
color="player",
line_close=True,
color_discrete_sequence=["#00eb93", "#4ed2ff"],
template="plotly_dark")
fig.update_polars(angularaxis_showgrid=False,
radialaxis_gridwidth=0,
gridshape='linear',
bgcolor="#494b5a",
radialaxis_showticklabels=False
)
fig.update_layout(paper_bgcolor="#2c2f36")
fig.show()
With the above code I don't think it is possible to modify the color of each nested shape. To be able to do so, you will probably have to create your own template and color each nested shape separately.
creating grid shape
You might have to try something similar the code below to create your desired grid shape.
import plotly.graph_objects as go
bgcolors = ["#353841", "#3f414d", "#494b5a", "#494b5a", "#58596a"]
fig = go.Figure(go.Scatterpolar(
r=[42]*8,
theta=[0, 45, 90, 135, 180, 225, 270, 315],
marker_line_width=2,
opacity=0.8,
marker=dict(color=bgcolors[0])
))
for i in range(1, 5):
fig.add_trace(go.Scatterpolar(
r=[44-6*i]*8,
theta=[0, 45, 90, 135, 180, 225, 270, 315],
marker_line_width=2,
marker=dict(color=bgcolors[i])
))
fig.update_polars(angularaxis_dtick='')
fig.update_traces(fill='toself')
fig.update_polars(angularaxis_showgrid=False,
radialaxis_showgrid=False,
radialaxis_gridwidth=0,
gridshape='linear',
radialaxis_showticklabels=False,
angularaxis_layer='above traces'
)
fig.show()
The colors are off the general shape is good.

Related

is there any way to get plotly radar charts with a complete line using go.Scatterpolar()?

In plotly's example scatter radar plots (here), one of the line segments is missing. This is also the case when I've tried it myself - I think if you're using plotly express you can use line_close. Is there an equivalent in using go.Scatterpolar?
The examples in the reference are created in a graph object and the lines are not closed. To close it, the data must be adjusted. This is accomplished by repeating the first point.
import plotly.graph_objects as go
r = [1, 5, 2, 2, 3]
r.append(r[0])
theta = ['processing cost','mechanical properties','chemical stability','thermal stability','device integration','processing cost']
theta.append(theta[0])
fig = go.Figure(data=go.Scatterpolar(
r=r,
theta=theta,
fill='toself'
))
fig.update_layout(autosize=False,
height=450,
polar=dict(
radialaxis=dict(
visible=True
),
),
showlegend=False)
fig.show()

Show name of a trace on scatterpolar chart all the time without needing to hover over it

I am trying to figure out if there is a way to have the name of a Python plotly scatterpolar trace to always be visible, rather than having to hover over each trace on the graph. This is what I have so far in terms of code.
import plotly.graph_objects as go
categories = ['Passing', 'Dribbling', 'Shooting', 'Defense', 'Fitness']
fig = go.Figure()
fig.add_traces(go.Scatterpolar(
r=[6.33, 3.71, 0, 5.45, 5],
theta=categories,
fill='toself',
name='Team Average'
))
fig.add_traces(go.Scatterpolar(
r=[9.38, 2.86, 0, 5.0, 5.6],
theta=categories,
fill='toself',
name='Player Average'
))
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=False,
range=[0,10]
)
),
showlegend=False
)
fig.show()
And this is what the current scatterpolar chart looks like when I run it. As you can see, it does not show the names of each of the traces, and only appears when I hover over each trace.
With a go.Scatterpolar chart, text annotations are difficult because you will need to specify the cartesian x- and y-coordinates for the text annotations. Polar coordinates for text annotations inside the chart are not yet available, at least according to the linked Plotly forum post. While you could convert the polar coordinates of each point to x- and y-coordinates, and then add text at each of these locations, this seems like a heavy handed solution unless it's really necessary.
One compromise would be to use px.line_polar to draw the chart, and use the text argument to specify what text gets added for each point. Unfortunately you can only choose one field from your data (in your case, you can choose to display the value that you are passing to parameter r, or the category that you are passing to parameter theta).
To make px.line_polar look like go.Scatterpolar, you will want to add filling between the lines. In addition, to add the second px.line_polar chart on top of the first one, you'll need to create a new figure, then add that figure's data as a trace. You will also need to manually specify the color of the second px.line_polar chart.
import plotly.express as px
import plotly.graph_objects as go
categories = ['Passing', 'Dribbling', 'Shooting', 'Defense', 'Fitness']
fig = go.Figure()
fig = px.line_polar(
{'Team Average':[6.33, 3.71, 0, 5.45, 5], 'direction':categories},
r="Team Average",
theta="direction",
start_angle=360,
line_close=True,
text="Team Average",
)
fig2 = px.line_polar(
{'Player Average':[9.38, 2.86, 0, 5.0, 5.6], 'direction':categories},
r="Player Average",
color_discrete_sequence=["salmon"]*5,
theta="direction",
start_angle=360,
line_close=True,
text="Player Average",
)
## add fig2 to fig
fig.add_trace(fig2.data[0])
fig.update_traces(textposition='top center', fill='toself')
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=False,
range=[0,10]
)
),
showlegend=False
)
fig.show()

plotly: how to add different vertical lines in strip plot with categorical x-axis

I have a simple strip plot with a categorical x-axis. I want to add a vertical line (on different y-values) for each category.
I am able to to create one vertical line throughout the plot like this:
import plotly.express as px
fig = px.strip(df, x="category", y="value")
fig.add_hline(y=191)
Result looks like this:
However, I am unable to plot one vertical line for each category.
Desired Output
My desired output is something like this:
I tried adding a shape to the layout, but it did not affect the output:
fig.update_layout(shapes=[
dict( type= 'line',
yref= 'paper', y0= 180, y1= 180,
xref= 'x', x0= "cat1", x1= "cat1")])
Something like this would probably work if the x-axis is numeric. However, not sure how to specify the category here. If this is the way to go, then I am probably doing it wrong.
How would I be able to add a single horizontal line, as depcited above, with a different y-value for each category?
Data to reproduce plot:
import pandas as pd
df = pd.DataFrame(data={
"category": ["cat1", "cat1", "cat2", "cat2"],
"value": [150, 160, 180, 190]
})
Add lines with shapes. There are two types of coordinate axes: x,y axis and paper-based. From your desired output, you can read and specify the x-axis as paper-based and the y-axis as the y-axis value.
import pandas as pd
import plotly.express as px
df = pd.DataFrame({'category':['cat1','cat1','cat2','cat2'],'value':[150,160,180,190]})
fig = px.strip(df, x="category", y="value")
fig.update_layout(shapes=[dict(type='line', x0=0.2, y0=180, x1=0.3, y1=180,
xref='paper', yref='y',
line_width=3, line_color='red'),
dict(type='line', x0=0.7, y0=192, x1=0.8, y1=192,
xref='paper', yref='y',
line_width=3, line_color='red'),
])
fig.show()

Hoverinformation for shapes in plotly

I know there is the hovertemplate/hover_text/ option for traces (marker/line) but I cannot find such a thing for shapes.
Is there a way to have a hover text pop up when moving over a shape? Maybe a workaround?
Example:
import plotly.graph_objects as go
fig = go.Figure()
fig.add_trace(go.Scatter(
x=[1.5, 3],
y=[2.5, 2.5],
text=["Rectangle reference to the plot",
"Rectangle reference to the axes"],
mode="markers",
))
fig.add_shape(
# Rectangle reference to the plot
type="rect",
xref="paper",
yref="paper",
x0=0.25,
y0=0,
x1=0.5,
y1=0.5,
line=dict(
color="LightSeaGreen",
width=3,
),
fillcolor="PaleTurquoise",
)
When I hover over the two points, I get a hover-template with information. How can I get something similar for the shape?
It seems that it's not possible to add hoverinfo to shapes directly. But you can obtain something very close to what seems to be the desired effect through the right combination of shapes and traces. The following plot is made from specifying two rectangles in a list like:
shapes = [[2,6,2,6],
[4,7,4,7]]
The rest of the code snippet is set up to be flexible with regards to the number of shapes, and the colors assigned to them and the corresponding traces to make that little dot in the lower right corners of the shapes.
Plot:
If this is something you can use, we can discuss ways to edit what is being displayed in the hoverinfo.
Complete code:
# Imports
import pandas as pd
#import matplotlib.pyplot as plt
import numpy as np
import plotly.graph_objects as go
import plotly.express as px
# shape definitions
shapes = [[2,6,2,6],
[4,7,4,7]]
# color management
# define colors as a list
colors = px.colors.qualitative.Plotly
# convert plotly hex colors to rgba to enable transparency adjustments
def hex_rgba(hex, transparency):
col_hex = hex.lstrip('#')
col_rgb = list(int(col_hex[i:i+2], 16) for i in (0, 2, 4))
col_rgb.extend([transparency])
areacol = tuple(col_rgb)
return areacol
rgba = [hex_rgba(c, transparency=0.4) for c in colors]
colCycle = ['rgba'+str(elem) for elem in rgba]
# plotly setup
fig = go.Figure()
# shapes
for i, s in enumerate(shapes):
fig.add_shape(dict(type="rect",
x0=s[0],
y0=s[2],
x1=s[1],
y1=s[3],
layer='above',
fillcolor=colCycle[i],
line=dict(
color=colors[i],
width=3)))
# traces as dots in the lower right corner for each shape
for i, s in enumerate(shapes):
fig.add_trace(go.Scatter(x=[s[1]], y=[s[2]], name = "Hoverinfo " +str(i + 1),
showlegend=False,
mode='markers', marker=dict(color = colors[i], size=12)))
# edit layout
fig.update_layout(yaxis=dict(range=[0,8], showgrid=True),
xaxis=dict(range=[0,8], showgrid=True))
fig.show()
I thought of a solution I am happy with.
Simply draw a shape. You won't be able to see a hover text. However, if you add a trace with a fill on top of the shape, then set the trace to opacity=0 you will see the hover text from the trace pop up when moving over the shape.
Again, thanks for your responses!
import plotly.graph_objects as go
# Draw shape (you won't be able to add a hover text for it)
fig = go.Figure()
fig.add_shape(
type="rect",
x0=0, y0=0,
x1=4, y1=3,
fillcolor='LightSkyBlue',
line_color='Blue',
name='Shape 1'
)
# Adding a trace with a fill, setting opacity to 0
fig.add_trace(
go.Scatter(
x=[0,0,4,4,0],
y=[0,3,3,0,0],
fill="toself",
mode='lines',
name='',
text='Custom text on top of shape',
opacity=0
)
)
fig.show()

How do you add labels to a plotly boxplot in python?

I have the following code;
y = errnums
err_box = Box(
y=y,
name='Error Percent',
boxmean='sd',
marker=Marker(color='red'),
boxpoints='all',
jitter=0.5,
pointpos=-2.0
)
layout = Layout(
title='Error BoxPlot',
height=500,
width=500
)
fig = Figure(data=Data([err_box]), layout=layout)
plotly.image.save_as(fig, os.path.join(output_images, 'err_box.png'))
Which generates the following image;
What I would like to do is the following two things;
1) Add % next to the y-axis numbers. (Instead of having a traditional y-axis label saying "Error (%)")
2) Label all the vital points: mean, first quartile, third quartile, and stdev. Ideally the label would be a 4 sig-fig ('.2f') number next to the line.
Also, the stdev is the dotted line, and the diamond represents 1 sigma? 2 sigma?
For labels, try annotations. You'll have to compute the quartiles and mean yourself to position the labels.
Simple example:
import plotly.plotly as py
from plotly.graph_objs import *
data = Data([
Box(
y=[0, 1, 1, 2, 3, 5, 8, 13, 21],
boxpoints='all',
jitter=0.3,
pointpos=-1.8
)
])
layout = Layout(
annotations=Annotations([
Annotation(
x=0.3,
y=8.822,
text='3rd Quartile',
showarrow=False,
font=Font(
size=16
)
)
])
)
fig = Figure(data=data, layout=layout)
plot_url = py.plot(fig)
Simple Python boxplot
I recommend adding and positioning the annotations in the Plotly workspace, and then viewing the generated code:
The diamond shows the mean, and +- 1 standard deviation away from it.
It's not currently possible to add a % to the y-axis labels.

Categories