How to plot a ternary chart with lines using Plotly python? - python

I need to create a kind of "ternary" chart but instead of showing only points I need to set the lines, similar to the chart below:
I have created a data sample but I'm not 100% sure that this it has the correct data structure to build the chart
import pandas as pd
dummy_data=[{"var1":0.74, "var2":.60, "var3":.78, "comp":"option1"},
{"var1":0.8, "var2":0.75, "var3":0.72, "comp":"option2"}]
table=pd.DataFrame.from_dict(dummy_data)
I did a lot of searches but the most similar alternative I found was scatter_ternary which only plots points;
Any help will be very welcome!
Thank you in advance;
Regards,
Leonardo

I am new to this chart. I created the graph by replacing the examples in the official reference with lines. First of all, I needed four pieces of data from the start point to the end point. A->B->C->A Then the sum of the ABC points of that data must be the same. In my example, the sum is 1. After that I added the graph with as much triangular data as I needed.
import pandas as pd
dummy_data=[
{"var1":0.7, "var2":0.15, "var3":0.15, "comp":"option1"},
{"var1":0.15, "var2":0.7, "var3":0.15, "comp":"option1"},
{"var1":0.15, "var2":0.15, "var3":0.7, "comp":"option1"},
{"var1":0.7, "var2":0.15, "var3":0.15, "comp":"option1"},
{"var1":0.6, "var2":0.2, "var3":0.2, "comp":"option2"},
{"var1":0.2, "var2":0.6, "var3":0.2, "comp":"option2"},
{"var1":0.2, "var2":0.2, "var3":0.6, "comp":"option2"},
{"var1":0.6, "var2":0.2, "var3":0.2, "comp":"option2"}
]
table=pd.DataFrame.from_dict(dummy_data)
import plotly.graph_objects as go
fig = go.Figure()
table1 = table[table['comp'] == 'option1']
fig.add_trace(go.Scatterternary(
text=table1['comp'],
a=table1['var1'],
b=table1['var2'],
c=table1['var3'],
mode='lines',
line_color='red',
name='option1'
))
table2 = table[table['comp'] == 'option2']
fig.add_trace(go.Scatterternary(
text=table2['comp'],
a=table2['var1'],
b=table2['var2'],
c=table2['var3'],
mode='lines',
line_color='black',
name='option2'
))
fig.update_layout({
'title': 'Ternary Line Plot',
'ternary':
{
'sum':1,
'aaxis':{'title': 'A', 'min': 0.01, 'linewidth':2, 'ticks':'outside' },
'baxis':{'title': 'B', 'min': 0.01, 'linewidth':2, 'ticks':'outside' },
'caxis':{'title': 'C', 'min': 0.01, 'linewidth':2, 'ticks':'outside' }
},
'showlegend': False
})
fig.update_layout(showlegend=True)
fig.show()

Related

How to target a specific trace in pie chart by name when using update_traces() selector attribute?

The idea is to change the hover template only in the "Resto" trace. Here is a reproducible example:
df_stack = pd.DataFrame({"Country": ['Brasil','China','Estados unidos','Chile','India','Paises bajos','Vietnam','Peru','Corea, republica de','Indonesia','Resto'],
"Dolars": [11599.42961799,7671.6791054099995,6198.81430321,4578.07,4153.13352132,3352.11349841,2998.44092833,2247.29957849,1968.7549113200002,1890.7284090800001,35635.107780379985],
"Pct_change":[0.0846110761489467,0.2953716769009316,0.41561413372310074,0.21787800280514857,0.09245460739576772,0.18325289020293622,0.023857445957433443,0.2555960957383905,0.2319776811635097,0.12068329801455069,0.0]
})
fig = go.Figure(data=[go.Pie(labels=df_stack["Country"], values=df_stack['Dolars'], hole=.5,
customdata = np.transpose([df_stack["Pct_change"],
]),
hovertemplate="<b>%{label}</b> <br>Dolars: $%{value:,.2f}"
"<br>Percent: %{percent:.1%}"
"<br>Pct_change: %{customdata[0]:.1%}"
"<br<extra></extra>>",
)])
fig.update_layout(title_text = f"Change hover of specific trace in pie chart", template = None, font_family = "verdana",
margin = dict(t=70, l=10, r=10, b=30), separators = ",.",
showlegend= False,)
fig.update_traces(hovertemplate=None, selector=dict(name = 'Resto')) #It won't work!!!
Unlike with Scatter traces, the last line of code won't do the trick.
fig.update_traces(hovertemplate=None, selector=dict(name = 'Resto')) #It won't work!!!
Help is much appreciated!
r-beginners is right, and I would like to add a few details that I hope will be of interest.
Generally, unique hovertemplates can only be applied to specific traces. So as long as you've got different traces within a figure object, you can apply any hovertemplate you would like to each trace. Unfortunately, a Plotly pie chart consists of only one trace, even though it might not look like that since you've got different colors in the pie chart.
There are a few details in your code that reveal how these things are tied together. When you construct a pie chart with go.Figure(go.Pie()), you're creating one figure object containing one trace.
And if you take a look at the structure of your pie chart with fig.data, you'll see how hovertemplate is associated with the only trace there:
(Pie({
'customdata': array([[0.08461108],
[0.29537168],
[0.41561413],
[0.217878 ],
[0.09245461],
[0.18325289],
[0.02385745],
[0.2555961 ],
[0.23197768],
[0.1206833 ],
[0. ]]),
'hole': 0.5,
'hovertemplate': ('<b>%{label}</b> <br>Dolars: $%' ... 'ata[0]:.1%}<br<extra></extra>>'),
'labels': array(['Brasil', 'China', 'Estados unidos', 'Chile', 'India', 'Paises bajos',
'Vietnam', 'Peru', 'Corea, republica de', 'Indonesia', 'Resto'],
dtype=object),
'values': array([11599.42961799, 7671.67910541, 6198.81430321, 4578.07 ,
4153.13352132, 3352.11349841, 2998.44092833, 2247.29957849,
1968.75491132, 1890.72840908, 35635.10778038])
}),)
And what fig.update_traces(selector=... would potentially do for you is apply your desired hovertemplate to a trace within a figure object. If you were to try to construct a pie chart with multiple traces with fig.add_trace like this:
import plotly.graph_objects as go
fig = go.Figure()
fig.add_trace(go.Pie(values = [1,2,3]))
fig.add_trace(go.Pie(values = [5,6,7]))
Then each fig.add_trace would only overwrite the single existing trace in your figure object, so there's not much help there either.
I hope this clarifies things a bit, and that you are able to find other methods to convey the information in your visualization.

How to subplot histogram using multiple columns with plotly?

So I have data that I transformed up to this point (pic below). How can I now subplot histograms that will show me the programming languages used per job? I tried with just 2 columns at first:
px.histogram(languages_job_title_grouped, x =['Python','SQL'], facet_col = 'Role', facet_col_wrap = 4,height = 1000)
But it didn't work - it plots histogram by job, but the bars are the same for every role (2nd picture below).
How can I do it the right way?
From the context of your question, it seems like you are looking for a bar plot instead.
I.e. If I understand correctly, you are starting from a dataframe equivalent to
and trying to plot
where the facets are the index, the x-axis is each column, and the bar heights are the values in the dataframe.
The code that generates this is:
import pandas as pd
import plotly.express as px
df = pd.DataFrame(
[[0.1, 0.3, 0.5], [0.2, 0.1, 0.8], [0.5, 0.3, 0.9]],
columns=["a", "b", "c"],
index=["index1", "index2", "index3"],
)
px.bar(
df.melt(ignore_index=False).reset_index(),
facet_col="index",
x="variable",
y="value",
barmode="group",
)
The key being to reformat your DataFrame using melt before trying to plot with plotly.express.

How do I add a secondary legend that explains what symbols mean with plotly express?

I have a plot which uses US states to map symbols. I currently assign symbols using the "state" column in my dataframe so that I can select particular states of interest by clicking or double clicking on the Plotly Express legend. This part is working fine. However, the symbol mapping I'm using also communicates information about territory, e.g. triangle-down means poor coverage in that state and many states will share this symbol. I would like to add another legend that shows what each shape means. How can I do this in Plotly Express? Alternatively, is there a way to display symbols in a footnote? I could also give the symbol definitions there.
The goal is to display that circle=Medium coverage, triangle-down=poor coverage, etc. in addition to the individual state legend I already have. If the legend is clickable such that I can select entire groups based on the symbol shape that would be the best possible outcome.
Thank you for any tips!
I tried using html and footnotes to display the symbols but it did not work.
as noted in comment, it can be achieved by additional traces on different axes
have simulated some data that matches what is implied in image and comments
from scatter figure extract out how symbols and colors have been assigned to states
build another scatter that is effectively a legend.
import pandas as pd
import numpy as np
import plotly.express as px
df_s = pd.read_html(
"https://en.wikipedia.org/wiki/List_of_states_and_territories_of_the_United_States"
)[1].iloc[:, 0:2]
df_s.columns = ["name", "state"]
# generate a dataframe that matches structure in image and question
df = pd.DataFrame(
{"activity_month": pd.date_range("1-jan-2020", "today", freq="W")}
).assign(
value=lambda d: np.random.uniform(0, 1, len(d)),
state=lambda d: np.random.choice(df_s["state"], len(d)),
)
# straight forward scatter
fig = px.scatter(df, x="activity_month", y="value", symbol="state", color="state")
# extract out how symbols and colors have been assigned to states
df_symbol = pd.DataFrame(
[
{"symbol": t.marker.symbol, "state": t.name, "color": t.marker.color}
for t in fig.data
]
).assign(y=lambda d: d.index//20, x=lambda d: d.index%20)
# build a figure that effectively the legend
fig_legend = px.scatter(
df_symbol,
x="x",
y="y",
symbol="symbol",
color="state",
text="state",
color_discrete_sequence=df_symbol["color"]
).update_traces(textposition="middle right", showlegend=False, xaxis="x2", yaxis="y2")
# insert legend into scatter and format axes
fig.add_traces(fig_legend.data).update_layout(
yaxis_domain=[.15, 1],
yaxis2={"domain": [0, .15], "matches": None, "visible": False},
xaxis2={"visible":False},
xaxis={"position":0, "anchor":"free"},
showlegend=False
)

How plot points based on categorical variable in plotly

I am using Plotly for visualization. I want to make plot, and give the points colors based on categorical variable.
fig = go.Figure()
fig.add_trace(go.Scatter(x=df.Predicted, y=df.Predicted,colors='Category',mode='markers',
))
fig.add_trace(go.Scatter(x=df.Predicted, y=df.real , colors='Category'
))
fig.show()
where Category is column in my dataframe. How can I do this kind of graph
you have implied a data frame structure which I have simulated
it's simpler to use Plotly Express higher level API that graph objects
have used to calls to px.scatter() to generate traces defined in your question. Plus have renamed traces in second call to ensure legend is clear and made them lines
import numpy as np
import pandas as pd
import plotly.express as px
df = pd.DataFrame(
{
"Predicted": np.sort(np.random.uniform(3, 15, 100)),
"real": np.sort(np.random.uniform(3, 15, 100)),
"Category": np.random.choice(list("ABCD"), 100),
}
)
px.scatter(df, x="Predicted", y="Predicted", color="Category").add_traces(
px.line(df, x="Predicted", y="real", color="Category")
.for_each_trace(
lambda t: t.update(name="real " + t.name)
) # make it clear in legend this is second set of traces
.data
)

How to format plotly legend when using marker color?

I want to follow up on this post: Plotly: How to colorcode plotly graph objects bar chart using Python?.
When using plotly express, and specifying 'color', the legend is correctly produced as seen in the post by vestland.
This is my plotly express code:
data = {'x_data': np.random.random_sample((5,)),
'y_data': ['A', 'B', 'C', 'D', 'E'],
'c_data': np.random.randint(1, 100, size=5)
}
df = pd.DataFrame(data=data)
fig = px.bar(df,
x='x_data',
y='y_data',
orientation='h',
color='c_data',
color_continuous_scale='YlOrRd'
)
fig.show()
But when using go.Bar, the legend is incorrectly displayed as illustrated here:
This is my code using graph objects:
bar_trace = go.Bar(name='bar_trace',
x=df['x_data'],
y=df['y_data'],
marker={'color': df['c_data'], 'colorscale': 'YlOrRd'},
orientation='h'
)
layout = go.Layout(showlegend=True)
fig = go.FigureWidget(data=[bar_trace], layout=layout)
fig.show()
I'm learning how to use FigureWidget and it seems it can't use plotly express so I have to learn how to use graph objects to plot. How do I link the legend to the data such that it works like the plotly express example in vestland's post.
This really comes down to understanding what a high level API (plotly express) does. When you specify color in px if it is categorical it creates a trace per value of categorical. Hence the below two ways of creating a figure are mostly equivalent. The legend shows an item for each trace, not for each color.
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
df = pd.DataFrame({"x":np.linspace(0,10,10), "y":np.linspace(5,15,10), "color":np.random.choice(list("ABCD"),10)})
px.bar(df, x="x", y="y", color="color", orientation="h").show()
fig = go.Figure()
for g in df.groupby("color"):
fig.add_trace(go.Bar(x=g[1]["x"], y=g[1]["y"], name=g[0], orientation="h"))
fig
supplementary based on comments
you do not have to use graph objects if you are using FigureWidget() as demonstrated by second figure, create with plotly express and then generate FigureWidget()
for continuous data normal pattern is to use a single trace and a colorbar (also demonstrated in second figure). However if you want a discrete legend, create a trace per value in c_data and use https://plotly.com/python-api-reference/generated/plotly.colors.html sample_colorscale()
import plotly.express as px
import plotly.colors
import plotly.graph_objects as go
import numpy as np
import pandas as pd
# simulate data frame...
df = pd.DataFrame(
{
"x_data": np.linspace(0, 10, 10),
"y_data": np.linspace(5, 15, 10),
"c_data": np.random.randint(0, 4, 10),
}
)
# build a trace per value in c_data using graph objects ... correct legend !!??
bar_traces = [
go.Bar(
name="bar_trace",
x=d["x_data"],
y=d["y_data"],
marker={
"color": plotly.colors.sample_colorscale(
"YlOrRd",
d["c_data"] / df["c_data"].max(),
)
},
orientation="h",
)
for c, d in df.groupby("c_data")
]
layout = go.Layout(showlegend=True)
fig = go.FigureWidget(data=bar_traces, layout=layout)
fig.show()
fig = px.bar(
df,
x="x_data",
y="y_data",
color="c_data",
orientation="h",
color_continuous_scale="YlOrRd",
)
fig = go.FigureWidget(data=fig.data, layout=fig.layout)
fig.show()

Categories