I couldn't find the way to add text labels to plotly/dash box plot like you could add it to a scatterplot. In the example below, for ScatterPlot x=qty, y=price and you can then add Salesperson to the graph when the cursor is on Marker. For adding this I use the 'text' argument.
In the second example for BoxPlot when x=date, y=price I want to add salesperson in the same way. It would be very useful in case of outliers to see immediately who was the salesperson for that purchase. I looked in the documentation, but there is no clue. I assume it's not possible but still decided to try my luck here.
scatterplot:
import plotly.offline as pyo
import plotly.graph_objs as go
purchase={'date':['11/03/2021','12/03/2021','14/03/2021','11/03/2021'],
'price':[300, 400,200, 200],
'currency':['eur', 'usd','usd','usd'],
'qty':[200, 300, 400, 500],
'salesman':['AC', 'BC', "CC", 'DC']}
pur=pd.DataFrame(purchase)
pur
data = [go.Scatter(
x = pur['qty'],
y = pur['price'],
mode = 'markers',
text=pur['salesman'],
marker = dict(
size = 12,
color = 'rgb(51,204,153)',
symbol = 'pentagon',
line = dict(
width = 2,
)
)
)]
layout = go.Layout(
title = 'Random Data Scatterplot',
xaxis = dict(title = 'Some random x-values'),
yaxis = dict(title = 'Some random y-values'),
hovermode ='closest'
)
fig = go.Figure(data=data, layout=layout)
fig.show()
boxplot:
import plotly.offline as pyo
import plotly.graph_objs as go
x = pur['date']
y = pur['price']
data = [
go.Box(
y=y,
x=x,
text=pur['salesman']
)
]
layout = go.Layout(
title = 'box_plot'
)
fig = go.Figure(data=data, layout=layout)
fig.show()
The data you currently have is not suitable for boxplot. If you try to plot a boxplot with your data, the list [300, 400,200, 200] is used only once for the first date. For the other dates, there is no data.
I will show a simpler example with my own data.
dataset.csv
salesman,sales
alan,1.8
bary,2.3
copa,4.2
dac,1.19
eila,2.3
foo,2.5
gary,0.1
holland,10
code
import plotly.graph_objs as go
import pandas as pd
import plotly.io as pio
pio.renderers.default = 'browser'
df = pd.read_csv("deletelater")
fig = go.Figure()
fig.add_trace(go.Box(
y=df["sales"],
name='12/12/22',
customdata=df["salesman"],
hovertemplate='<b>sales: %{y}</b><br>salesperson: %{customdata}'
))
fig.show()
Diagram
As you can see, the name of the outlier salesperson is displayed on the hover label.
Related
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()
I have 2 csv files, my codes are as below.
df = pd.read_csv("test.csv",
sep='\t',skiprows=range(9),names=['A', 'B', 'C','D'])
df2 = pd.read_csv("LoadMatch_Limit.csv",skiprows=range(1),names=['X','Y'])
fig = px.line([df,df2], x=['A','X'] , y=['D','Y'])
I would like my line chart, x-axis to take from (columns 'A' and 'X') and my y-axis to take from (columns 'D' and 'Y').
Is there anyway I can plot these 2 charts as one figure?
You could create the two plots and combine them with plotly graph objects
import plotly.express as px
import plotly.graph_objects as go
fig1 = px.line(df, x='A', y='D')
fig2 = px.line(df2, x='X', y='Y')
fig = go.Figure(data = fig1.data + fig2.data)
fig.show()
Plotly.offline has no attribute line. You need to use the graph object to plot two graphs in a single figure. A simple example is shown below(run the code below and see the output graph)
import numpy as np
import pandas as pd
import plotly.offline as py
import plotly.graph_objs as go
from plotly import tools
df1 = pd.DataFrame({"X":np.linspace(0,30,10), "Y":np.random.rand(10)})
df2 = pd.DataFrame({"A":np.linspace(0,40,10), "B":np.random.rand(10)})
# plotting the graphs...
# 'rgb(128, 0, 128)'
# color=sns.color_palette()
def scatter_chart(x, y, color, name):
trace = go.Scatter(
x=x.values,
y=y.values,
name=name,
marker=dict(
color=color,
line=dict(
color=color,
width=1)
),
)
return trace
trace1 = scatter_chart(df2["A"], df2["B"], 'rgb(128, 0, 128)', "df2")
trace2 = scatter_chart(df1["X"], df1["Y"], 'rgba(50, 171, 96, 0.6)', "df1")
fig = tools.make_subplots(rows=1,cols=1, vertical_spacing=0.5)
fig.add_trace(trace1)
fig.add_trace(trace2)
fig.update_layout(
title="df2 and df1 plot",
height=600,
width=600,
# annotations=annotations,
xaxis=dict(tickangle=-45),
legend=dict(x=0.029, y=1.038, font_size=10),
margin=dict(l=100, r=20, t=70, b=70),
paper_bgcolor='rgb(248, 248, 255)',
plot_bgcolor='rgb(248, 248, 255)',)
py.iplot(fig, filename='pageviews_plots_4')
I am trying to make an interactive plot with a dropdown menu that selects from a series of wholly unrelated figures (i.e. plots that rely on different data structures and that have very different layouts). All of the dropdown menu examples I have seen are based on either a single set of data or multiple datasets but that use a relatively simple plot layout. This is not applicable to my case where I am trying to merge dozens of plots with very different layouts and underlying data. Below is a working example of the plots that I am trying to merge. The layouts are highly different across each plot:
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
# Prep some fake data for a bar graph
df1 = pd.DataFrame(dict(
bar_y = ['Bar1', 'Bar2'],
bar_x = [2,3],
bar_z = [1,2]
))
# Make bar graph
fig1 = px.bar(df1,
x="bar_x",
y='bar_y',
color='bar_z',
orientation='h',
)
# Add layout attributes
fig1.update_layout(
xaxis_title="<b> Bar graph title <b>",
yaxis_title="<b> Bar x axis <b>",
legend_title="<b> Bar y axis <b>",
xaxis = dict(
showgrid=True,
ticks="",
showline = False,
gridcolor = 'white'
)
)
# Prep some fake data for a line graph
df2 = pd.DataFrame(dict(
line_y = [3,2,1, 1,2,3],
line_x = [1,2,3,1,2,3],
line_group = ['line1','line1','line1','line2','line2','line2']
))
# Make an ugly line graph
fig2 = px.line(
df2,
x= 'line_x',
y= 'line_y',
color = 'line_group'
)
# Add a number of layout attributes that are distinct from those above
fig2.update_layout(
shapes=[dict(
type= 'line',
fillcolor = 'black',
line_width=2,
yref= 'y', y0= 0, y1= 0,
xref= 'x', x0= 1, x1= 3,
)],
xaxis_title="<b> Line graph title <b>",
yaxis_title="<b> Line x axis <b>",
legend_title="<b> Line y axis <b>",
template='simple_white',
hoverlabel=dict(bgcolor="white")
)
# Create a dropdown menu. Below is close to what I'd like to do, but the data statements are not working correctly and the shape in fig2 is causing problems...
fig3 = go.Figure()
fig3.update_layout(
updatemenus=[
dict(
active=0,
buttons=list([
dict(label="Bar Graph",
method="update",
args=[fig1.to_dict()['data'],
fig1.to_dict()['layout']]
),
dict(label="Line Graph",
method="update",
args=[fig2.to_dict()['data'],
fig2.to_dict()['layout']]
),
]))
]
)
It appears that I am almost able to correctly update the layout of each dropdown constituent plot based on the layout of each original graph. However, is it possible to update the data via this sort of method
as well?
I may be missing the point completely here. And it may also be overkill to unleash a Dash app in this case. But I would like to show you how the following setup can enable you to return completely different figure objects using a dcc.Dropdown(). The code snippet below will produce the following app:
If you now select fig2, you'll get this:
We can talk more about the details if this is something you can use. Also, the design with the very wide dropdown button is admittedly not the prettiest one, but I assume that design isn't the primary objective here.
Complete code:
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output
import numpy as np
from plotly.subplots import make_subplots
import plotly.express as px
# Prep some fake data for a bar graph
df1 = pd.DataFrame(dict(
bar_y = ['Bar1', 'Bar2'],
bar_x = [2,3],
bar_z = [1,2]
))
# Make bar graph
fig1 = px.bar(df1,
x="bar_x",
y='bar_y',
color='bar_z',
orientation='h',
)
# Add layout attributes
fig1.update_layout(
xaxis_title="<b> Bar graph title <b>",
yaxis_title="<b> Bar x axis <b>",
legend_title="<b> Bar y axis <b>",
xaxis = dict(
showgrid=True,
ticks="",
showline = False,
gridcolor = 'white'
)
)
# Prep some fake data for a line graph
df2 = pd.DataFrame(dict(
line_y = [3,2,1, 1,2,3],
line_x = [1,2,3,1,2,3],
line_group = ['line1','line1','line1','line2','line2','line2']
))
# Make an ugly line graph
fig2 = px.line(
df2,
x= 'line_x',
y= 'line_y',
color = 'line_group'
)
# Add a number of layout attributes that are distinct from those above
fig2.update_layout(
shapes=[dict(
type= 'line',
fillcolor = 'black',
line_width=2,
yref= 'y', y0= 0, y1= 0,
xref= 'x', x0= 1, x1= 3,
)],
xaxis_title="<b> Line graph title <b>",
yaxis_title="<b> Line x axis <b>",
legend_title="<b> Line y axis <b>",
template='simple_white',
hoverlabel=dict(bgcolor="white")
)
# app = JupyterDash(__name__)
app = dash.Dash()
figs = ['fig1', 'fig2']
app.layout = html.Div([
html.Div([
dcc.Graph(id='plot'),
html.Div([
dcc.Dropdown(
id='variables',
options=[{'label': i, 'value': i} for i in figs],
value=figs[0]
)
])
])
])
#app.callback(
Output('plot', 'figure'),
[Input('variables', 'value')])
def update_graph(fig_name):
if fig_name == 'fig1':
# fig=go.Figure(go.Scatter(x=[1,2,3], y = [3,2,1]))
return fig1
if fig_name == 'fig2':
# fig=go.Figure(go.Bar(x=[1,2,3], y = [3,2,1]))
return fig2
# app.run_server(mode='external', debug=True)
app.run_server(debug=True,
use_reloader=False # Turn off reloader if inside Jupyter
)
I am trying to make a plot similar to the next one:
While I have until now is:
Which is generated with the following code:
import plotly.io as pio
pio.renderers.default='browser'
import plotly.graph_objects as go
import pandas as pd
import numpy as np
input_df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
threshold =2.8
name_yaxis="Gap"
input_df["AAPL.High"] = (input_df["AAPL.High"]-min(input_df["AAPL.High"]))*(threshold)/(max(input_df["AAPL.High"])-min(input_df["AAPL.High"]))+np.random.uniform(0.3,0.4,1)
fig = go.Figure()
fig.add_trace(go.Scatter(x=input_df['Date'], y=np.repeat(threshold,len(input_df)),
mode='lines',
name="Threshold",
line=dict(color="#EBB81C",dash='dash')))
fig.add_trace(go.Scatter(x=input_df['Date'], y=input_df['AAPL.High'],
mode='lines',
name='Rolling average(mm)',
line = dict(color="#C4C4C4")
)
)
fig.add_trace(go.Scatter(x=input_df['Date'], y=input_df['AAPL.High'],
mode='markers',
marker_size=12,
name='Healthy(mm)',
marker=dict(color=( (0 < input_df['AAPL.High']) & (input_df['AAPL.High'] < threshold)).astype('int'),
colorscale=['#A51890', '#3BBFFE']
),
showlegend=True
)
)
fig.update_layout(
xaxis = dict(title="Flight Operation date", tickfont=dict(
family="Roboto",size = 8), gridcolor='#e8e9eb'), # xaxis settings
yaxis = dict(title=name_yaxis, tickfont=dict(
family="Roboto",size = 10), gridcolor='#e8e9eb'), # yaxis settings
plot_bgcolor = "white", # set background color
legend = dict(title="<b>Health status<b>",traceorder="reversed",font = dict(family = "Roboto", size = 10)) # legend settings
)
I have a couple of questions about the legend:
How to show the purple color into the legend?
How to create multiple legends as the desired image?
Thanks in advance.
I made a line graph with the code below and I'm trying to add a horizontal line at y=1. I tried following the instructions on the plotly site but it is still not showing. Does anyone know why?
date = can_tot_df.date
growth_factor = can_tot_df.growth_factor
trace0 = go.Scatter(
x=date,
y=growth_factor,
mode = 'lines',
name = 'growth_factor'
)
fig = go.Figure()
fig.add_shape(
type='line',
x0=date.min(),
y0=1,
x1=date.max(),
y1=1,
line=dict(
color='Red',
)
)
data = [trace0]
iplot(data)
Short answer, and a general solution:
fig.add_shape(type='line',
x0=0,
y0=40,
x1=8,
y1=40,
line=dict(color='Red',),
xref='x',
yref='y'
)
Details and specifics about OP's question
It's hard to tell exactly what's wrong without a sample of your data.
What I can tell for sure is that you're missing the arguments xref and yref to specify that the line is drawn as units of your y and x axis. Judging by your sample code, this is what you'd like to do since you're specifying your x-values in terms of dates.
Also, you don't need to worry about iplot for newer versions of plotly. You can display your chart just as easily by just running fig.show(). The figure and code sample below will show you how to use fig.show() and how to define your lines in terms of axis units.
Plot:
Code:
import plotly.graph_objects as go
import numpy as np
x = np.arange(10)
fig = go.Figure(data=go.Scatter(x=x, y=x**2))
fig.add_shape(type='line',
x0=0,
y0=40,
x1=8,
y1=40,
line=dict(color='Red',),
xref='x',
yref='y'
)
fig.show()
An alternative to xref='x' is xref='paper'. Now you can specify x0 as a float between 0 and 1 spanning from the start and end of the plot.
You could also use fig.add_hline(y=1) --> see https://plotly.com/python/horizontal-vertical-shapes/
import plotly.graph_objects as go
import numpy as np
x = np.arange(10)
fig = go.Figure(data=go.Scatter(x=x, y=x**2))
fig.add_hline(y=40, line_width=3, line_dash="dash", line_color="green")
fig.show()
If you use subplots, then this is the easiest way I found to add an other line to a subplot. this example draws a horizontal line at y=80 for all x values
from plotly.subplots import make_subplots
fig = make_subplots(rows=2, cols=1,
shared_xaxes=True,
vertical_spacing=0.02)
[some graph]
fig.add_trace(go.Scatter(
name='Y=80',
x = [df['date'].min(), df['date'].max()],
y = [80, 80],
mode = "lines",
marker = dict(color = 'rgba(80, 26, 80, 0.8)')
),row=1, col=1)
i found the solution on github :
df = df
fig = px.scatter(df, x="date", y="growth_factor", mode = 'lines',
hover_name=df['growth_factor'] )
fig.update_layout(shapes=[
dict(
type= 'line',
yref= 'y', y0= 1, y1= 1, # adding a horizontal line at Y = 1
xref= 'paper', x0= 0, x1= 1
)
])
fig.show()
You’re adding the line to your fig object, but fig is not getting passed into the iplot() function, only your data. So only the trace is getting plotted.
If you're using a late version of plotly, the new syntax allows you to create this plot simply using the fig object, like:
from plotly import graph_objects as go
fig = go.Figure()
# Contrived dataset for example.
x = [1, 2, 3, 4]
y = [i**2 for i in x]
fig.add_trace(go.Scatter(
x=x,
y=y,
mode = 'lines',
name = 'growth_factor'))
fig.add_shape(type='line',
x0=min(x),
y0=5,
x1=max(x),
y1=5,
line=dict(color='Red'))
fig.update_shapes(dict(xref='x', yref='y'))
fig.show()
Here are the plotly docs for convenience.