Hi @qpoToH,
This idea of displaying multiple legends for different characteristics of the traces isn’t something that plotly.js support natively. In most cases, legends entries and traces have a 1 to 1 mapping. With that in mind, here’s an approach/work-around to getting what I think you’re looking for.
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
import plotly.graph_objs as go
import pandas as pd
init_notebook_mode(connected=True)
feed = pd.DataFrame({'AAPL': [100, 120, 130, 120, 150],
'MSFT': [80, 70, 90, 100, 99]}, index = pd.date_range('2018-01-01', '2018-01-05'))
trans = pd.DataFrame({'Symbol': ['AAPL', 'AAPL', 'MSFT', 'MSFT'],
'Amount': [2, 1, 3, 1],
'Action': ['buy', 'sell', 'buy', 'sell'],
'Price': [120, 150, 70, 100],
'Date': [pd.to_datetime(i) for i in ['2018-01-02', '2018-01-05', '2018-01-02', '2018-01-04']]
})
data = []
# Add "All" button
all_but = dict(label = 'All',
method = 'update',
args = [{'visible': [True]},
{'title': 'all'}
])
buttonlist = [all_but]
for i, col in enumerate(feed.columns.tolist()):
stock = go.Scatter(x=feed.index,
y=feed.loc[:, col],
name=col,
legendgroup='stock'
)
# actions
success = trans.loc[trans.Symbol == col]
# Buy
success_buy = success[success.Action == 'buy']
action_buy = go.Scatter(x=success_buy.Date,
y=success_buy.Price,
name='Buy',
mode = 'markers',
text = ['Amount ' + str(amount) for amount in success_buy.Amount],
hoverinfo = 'text',
showlegend=False,
marker = dict(
size=10,
color = 'green'
),
legendgroup='Buy',
)
# Sell
success_sell = success[success.Action == 'sell']
action_sell = go.Scatter(x=success_sell.Date,
y=success_sell.Price,
name='Sell',
mode = 'markers',
text = ['Amount ' + str(amount) for amount in success_sell.Amount],
hoverinfo = 'text',
showlegend=False,
marker = dict(
size=10,
color = 'red'
),
legendgroup='Sell',
)
data.append(stock)
data.append(action_buy)
data.append(action_sell)
button = dict(label = col,
method = 'update',
args = [{'visible': [col == i for i in feed.columns.tolist() for _ in range(3)] + [True, True]},
{'title': 'title' + col}
])
buttonlist.append(button)
# Add single buy and sell traces for legend
data.append(go.Scatter(x=[None], y=[None], mode='markers',
marker=dict(size=10, color='green'),
legendgroup='Buy', showlegend=True, name='Buy'))
data.append(go.Scatter(x=[None], y=[None], mode='markers',
marker=dict(size=10, color='red'),
legendgroup='Sell', showlegend=True, name='Sell'))
updatemenus = list([
dict(active=-1,
buttons=buttonlist,
)
])
layout = dict(title='Feed', showlegend=True,
updatemenus=updatemenus)
fig = dict(data=data, layout=layout)
iplot(fig)
A couple of notes:
- I split the buy and sell markers into two traces for each stock, that way they can show up separately on the legend.
- I placed all of the “Buy” traces in a
buy
legendgroup
and all of the “Sell” traces in asell
legendgroup
. This makes sure that when you click on the legend entries to hide/show, all of the “Buy”/“Sell” traces show and hide together. - I added two traces at the very end with
x
andy
of[None]
, one for buy and one for sell, added them to the corresponding legend group, and gave themshowlegend=True
. These traces don’t show up on the plot, but they do show up on the legend. And you can think of them as representing all of the other traces in the legend group in the legend.
Hope that helps!
-Jon