Plotly python add annotation to display all column values at every point - python

I am trying to plot all column values at each point when we hover over a data point in plotly
My code is as follows
import plotly.graph_objects as go
import plotly.io as pio
from plotly.subplots import make_subplots
import pandas as pd
# data
pio.templates.default = "plotly_white"
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
df_s = df[['Date','AAPL.Open','AAPL.High','AAPL.Low','dn','mavg'
]]
df_s = df_s.set_index('Date')
df_s.tail()
cols = df_s.columns
ncols = len(cols)
# subplot setup
fig = make_subplots(rows=ncols, cols=1, shared_xaxes=True)
for i, col in enumerate(cols, start=1):
fig.add_trace(go.Scatter(x=df_s[col].index, y=df_s[col].values, name=df_s[col].name), row=i, col=1)
fig.update_layout(
autosize=False,
width=1200,
height=800,)
fig.show()
Currently when I hover over the datapoint it shows value for that column alone. I am interested in seeing
Values for 'Date','AAPL.Open','AAPL.High','AAPL.Low','dn','mavg' these columns at a particular row whenever I hover over anyplot
I tried add_annotations with no luck. Is there a way of doing it? Thank you in advance

As #Marco_CH pointed out, this exact feature doesn't exist in Plotly. However, you can try using a unified hovermode on the x-axis so there is only one hoverbox, and remove the date from each hovertemplate since it's already shown at the top of the hoverbox.
import pandas as pd
import plotly.express as px
df = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv")
df1 = df.melt(id_vars=['Date']+list(df.keys()[5:]), var_name='AAPL')
fig = px.line(df1, x='Date', y='value', color='AAPL' )
## remove date from each hovertemplate
for fig_data in fig.data:
fig_data['hovertemplate'] = fig_data['hovertemplate'].replace("<br>Date=%{x}","")
fig.update_layout(hovermode="x unified")
fig.show()

No, this doesn't work. There is an open issue for this:
https://github.com/plotly/plotly.js/issues/4755
And it doesn't seem that this will come soon. You have to decide between your way and something like:
import pandas as pd
import plotly.express as px
pio.templates.default = "plotly_white"
df_s = pd.read_csv("https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv")
df_s = df_s.melt(id_vars=["Date"]+list(df.keys()[5:]), var_name="AAPL")
fig = px.line(df_s, x="Date", y="value", color="AAPL")
fig.update_layout(
autosize=False,
width=1200,
height=800,
hovermode="x")
fig.show()
Output:

Related

How to add an indicator of certain value on x-axis in plotly candlestick chart

I have a simple candle stick chart made with plotly.
import yfinance as yf
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
djia = yf.Ticker("DJIA")
df = djia.history(start="2022-01-01", end="2022-12-31", interval="1d")
fig = go.Figure()
fig = make_subplots(rows=1, cols=1)
# candlestick
fig.append_trace(
go.Candlestick(
x=df.index,
open=df["Open"],
high=df["High"],
low=df["Low"],
close=df["Close"]
), row=1, col=1
)
fig.update_xaxes(rangebreaks=[dict(bounds=["sat", "mon"])])
fig.show()
I don't know what it is called but I would like to add an indicator on x-axis to tell if certain condition is true during that the time frame of each candle. Here is a reference picture that explains what I'm looking for. The yellow and purple dots that are marked with the red square.
The idea would be to have an extra column in the dataframe with True/False values for each candle and that would be used to decide the color of the indicator dots. How could I achieve this?
A scatter plot is drawn on the current candlestick graph at the price 18 location. The color is determined by comparing the opening and closing prices. The easiest way to do this is to add a column of colors to the original data frame and set it to the color of the marker.
import yfinance as yf
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
djia = yf.Ticker("DJIA")
df = djia.history(start="2022-01-01", end="2022-12-31", interval="1d")
# color column add
df['colors'] = df[['Open', 'Close']].apply(lambda x: 'green' if x['Open'] <= x['Close'] else 'red', axis=1)
fig = go.Figure()
fig = make_subplots(rows=1, cols=1)
# candlestick
fig.append_trace(
go.Candlestick(
x=df.index,
open=df["Open"],
high=df["High"],
low=df["Low"],
close=df["Close"]
), row=1, col=1
)
fig.add_trace(go.Scatter(mode='markers', x=df.index, y=[18]*len(df), marker=dict(size=5, color=df['colors'])),row=1, col=1)
fig.update_xaxes(rangebreaks=[dict(bounds=["sat", "mon"])])
fig.update_layout(height=500)
fig.show()

Plotly: how to draw two linecharts with two dataframes with colors [duplicate]

I would like to create a subplot with 2 plot generated with the function plotly.express.line, is it possible? Given the 2 plot:
fig1 =px.line(df, x=df.index, y='average')
fig1.show()
fig2 = px.line(df, x=df.index, y='Volume')
fig2.show()
I would like to generate an unique plot formed by 2 subplot (in the example fig1 and fig2)
Yes, you can build subplots using plotly express. Either
1. directly through the arguments facet_row and facet_colums (in which case we often talk about facet plots, but they're the same thing), or
2. indirectly through "stealing" elements from figures built with plotly express and using them in a standard make_subplots() setup with fig.add_traces()
Method 1: Facet and Trellis Plots in Python
Although plotly.express supports data of both wide and long format, I often prefer building facet plots from the latter. If you have a dataset such as this:
Date variable value
0 2019-11-04 average 4
1 2019-11-04 average 2
.
.
8 2019-12-30 volume 5
9 2019-12-30 volume 2
then you can build your subplots through:
fig = px.line(df, x='Date', y = 'value', facet_row = 'variable')
Plot 1:
By default, px.line() will apply the same color to both lines, but you can easily handle that through:
fig.update_traces(line_color)
This complete snippet shows you how:
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
df = pd.DataFrame({'Date': ['2019-11-04', '2019-11-04', '2019-11-18', '2019-11-18', '2019-12-16', '2019-12-16', '2019-12-30', '2019-12-30'],
'variable':['average', 'volume', 'average', 'volume', 'average','volume','average','volume'],
'value': [4,2,6,5,6,7,5,2]})
fig = px.line(df, x='Date', y = 'value', facet_row = 'variable')
fig.update_traces(line_color = 'red', row = 2)
fig.show()
Method 2: make_subplots
Since plotly express can do some pretty amazing stuff with fairly complicated datasets, I see no reason why you should not stumple upon cases where you would like to use elements of a plotly express figure as a source for a subplot. And that is very possible.
Below is an example where I've built to plotly express figures using px.line on the px.data.stocks() dataset. Then I go on to extract some elements of interest using add_trace and go.Scatter in a For Loop to build a subplot setup. You could certainly argue that you could just as easily do this directly on the data source. But then again, as initially stated, plotly express can be an excellent data handler in itself.
Plot 2: Subplots using plotly express figures as source:
Complete code:
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
from plotly.subplots import make_subplots
df = px.data.stocks().set_index('date')
fig1 = px.line(df[['GOOG', 'AAPL']])
fig2 = px.line(df[['AMZN', 'MSFT']])
fig = make_subplots(rows=2, cols=1)
for d in fig1.data:
fig.add_trace((go.Scatter(x=d['x'], y=d['y'], name = d['name'])), row=1, col=1)
for d in fig2.data:
fig.add_trace((go.Scatter(x=d['x'], y=d['y'], name = d['name'])), row=2, col=1)
fig.show()
There is no need to use graph_objects module if you have just already generated px figures for making subplots. Here is the full code.
import plotly.express as px
import pandas as pd
from plotly.subplots import make_subplots
df = px.data.stocks().set_index('date')
fig1 = px.line(df[['GOOG', 'AAPL']])
fig2 = px.line(df[['AMZN', 'MSFT']])
fig = make_subplots(rows=2, cols=1)
fig.add_trace(fig1['data'][0], row=1, col=1)
fig.add_trace(fig1['data'][1], row=1, col=1)
fig.add_trace(fig2['data'][0], row=2, col=1)
fig.add_trace(fig2['data'][1], row=2, col=1)
fig.show()
If there are more than two variables in each plot, one can use for loop also to add the traces using fig.add_trace method.
From the documentation, Plotly express does not support arbitrary subplot capabilities. You can instead use graph objects and traces (note that go.Scatter is equivalent):
import pandas as pd
from plotly.subplots import make_subplots
import plotly.graph_objects as go
## create some random data
df = pd.DataFrame(
data={'average':[1,2,3], 'Volume':[7,3,6]},
index=['a','b','c']
)
fig = make_subplots(rows=1, cols=2)
fig.add_trace(
go.Scatter(x=df.index, y=df.average, name='average'),
row=1, col=1
)
fig.add_trace(
go.Scatter(x=df.index, y=df.Volume, name='Volume'),
row=1, col=2
)
fig.show()

Plotly Express Overlay Two Line Graphs

I know that it is easy to overlay plots using Plotly Go.
import plotly.graph_objects as go
fig = go.Figure()
fig.add_traces([go.Scatter(x=[1,2,3], y=[2,1,2]),
go.Scatter(x=[1,2,3], y=[2,1,2]),
go.Scatter(x=[1,2,3], y=[1,1,2])])
fig.show()
However, I would like to accomplish same task using Poltly Express. Is there a way to accomplish such a task in Plotly Express?
You can do it with add_traces
import pandas as pd
import numpy as np
import plotly.express as px
data = {'x':[1,2,3], 'y':range(3)}
df1 = pd.DataFrame(data)
data = {'x':[4,5,6], 'y':range(4,7)}
df2 = pd.DataFrame(data)
fig1 = px.line(df1, x='x', y='y', color_discrete_sequence=['red'])
fig2 = px.line(df2, x='x', y='y', labels='green', color_discrete_sequence=['green'])
fig1.add_traces(
list(fig2.select_traces())
)
name = ['red','green']
for i in range(len(fig1.data)):
fig1.data[i]['name'] = name[i]
fig1.data[i]['showlegend'] = True
fig1.show()
However, I prefer to use go plots, which are easier.

How to set color per column with Plotly

So simple and yet i just can't find solution after reading a lot.
I would like to plot 2 columns out of my dataframe (Pandas) and i want to set color for each.
color_dic = {"Close":'#565454',"MA":"red"}
fig = data.plot(x=data.index,y=["Close","MA"],template="simple_white",color=color_dic)
Which is not the way to do so, but what would be an equivalent way to get this ?
Also , how can i add a scatter on top of this with a different color ?
You can do this in many ways, and you can take a look at Plotly: How to define colors in a figure using plotly.graph_objects and plotly.express? for some details. But since you're specifically asking how to assign a color to a trace by the name of the source data in a pandas dataframe, I would use color_discrete_map = color_dict , where color_dict is a dictionary that contains {"Close":'#565454',"MA":"red"}, like this:
fig = df.plot(x=df.index,y=["Close","MA"],template="simple_white",
color_discrete_map = color_dict)
Plot 1:
To include another trace, I would use fig.update_trace along with the trace type of choice like this:
fig.add_trace(go.Scatter(x=df.index, y=df['Close']*2,
mode = 'lines',
line_color = 'blue'))
Plot 2:
Complete code:
import numpy as np
import pandas as pd
pd.options.plotting.backend = "plotly"
df = pd.DataFrame({"Close":[1,2,3,4,5,8,7,8],"MA":[2,2,2,3,4,4,6,7]})
color_dict = {"Close":'#565454',"MA":"red"}
fig = df.plot(x=df.index,y=["Close","MA"],template="simple_white",
color_discrete_map = color_dict)
fig.add_trace(go.Scatter(x=df.index, y=df['Close']*2,
mode = 'lines',
line_color = 'blue'))
fig.show()
there are many possibilities to plot with plotly, but if you use graphObject you can do:
import pandas as pd
import plotly.graph_objects as go
import plotly
data={"Close":[1,2,3,2,1,2,3,4],"MA":[0,1,2,3,4,5,2,1]}
df=pd.DataFrame(data)
fig = go.Figure()
color_dic = {"Close":'#565454',"MA":"red"}
# Add traces
for col in df.columns:
fig.add_trace(go.Scatter(x=df.index, y=df[col],
mode='lines+markers',
name=col,
marker_color=color_dic[col]))
result:

Plotly: How to plot multiple lines with shared x-axis?

I would like to have a multiple line plot within same canvas tied with the same x-axis as shown something in the figure:
Using subplots does not achieve the intended desire.
import plotly.express as px
from plotly.subplots import make_subplots
import plotly.graph_objects as go
fig = make_subplots(rows=2, shared_xaxes=True,vertical_spacing=0.1)
fig.add_scatter(y=[2, 1, 3], row=1, col=1)
fig.add_scatter(y=[1, 3, 2], row=2, col=1)
fig.show()
May I know how this can be done, appreciate if someone can point to good reading material
With a dataset such as this you can select any number of columns, set up a figure using fig = make_subplots() with shared_xaxes set to True and then add your series with a shared x-axis using fig.add_trace(go.Scatter(x=df[col].index, y=df[col].values), row=i, col=1) in a loop to get this:
Let me know if this is a setup you can use but need a little tweaking.
Complete code:
import plotly.graph_objects as go
import plotly.io as pio
from plotly.subplots import make_subplots
import pandas as pd
# data
pio.templates.default = "plotly_white"
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
df = df.set_index('Date')
df.tail()
cols = df.columns[:-4]
ncols = len(cols)
# subplot setup
fig = make_subplots(rows=ncols, cols=1, shared_xaxes=True)
for i, col in enumerate(cols, start=1):
fig.add_trace(go.Scatter(x=df[col].index, y=df[col].values), row=i, col=1)
fig.show()
Depending on the data you are plotting, I think you could either check out "Stacked Subplots with a Shared X-Axis (low-level API)" on https://plotly.com/python/subplots/
Or separate the data by shifting each line plot upwards like so:
import plotly.graph_objects as go
import random
data = []
n = 9
for x in range(10, 60, 10):
points = [value + x for value in random.sample(range(1,n+1), k = n)]
data.append(go.Scatter(y=points))
fig = go.Figure(data = data)
fig.show()

Categories