0
votes

I am attemping to develop an interactive dashboard using Plotly/Dash. The primary functionalities are:

  • (1) is to present multiple charts,
  • (2) with the same xaxis (timeseries),
  • (3) where both underlying data and specific the traces/lines can be interactively adjusted using callbacks.

Functionality (3) is ok and not a problem, so I will not include further in my description. However, (1) & (2) I cannot get to work.

To summarise what I have done so far for (1) & (2):
i. Create traces which refer to which chart the trace should be in (i.e. trace_01 & yaxis='y', trace_02 & yaxis='y2', etc);
ii. Specify yaxis, yaxis2, yaxis3, etc.
iii. Generate the rest of the dash application, as standard (i.e. go.Figure(data=data, layout=layout), dash.Dash(), etc.).

The problem is that I cannot get more than one set of traces on two (or more) charts (i.e. y-axis) with the same xaxis. I cannot get this to work.

CORE PROBLEM CODE:

# Set Traces/Data
t0101 = go.Scatter(x=df_fx.date, y=df_fx['close'],mode='lines',name='close',yaxis='y')
t0201 = go.Scatter(x=df_fx.date, y=df_fx['adx'],mode='lines',name='adx',yaxis='y2')
data = [t0101,t0201]

# Specify Layout
layout= go.Layout(
    xaxis= dict(side= 'bottom', anchor= 'y2'),
    yaxis= dict(side= 'right'),
    yaxis2= dict(side='left'),)

# Call Figure
fig = go.Figure(data=data, layout=layout)

# Create App
app = dash.Dash()
app.layout = html.Div([dcc.Graph(id='chart', figure=fig)])

This code generates the following output: output from code

What I really want to achieve is dashboard output such as: required output

It is important that the solution can be support Functionality (3), for example change the underlying data (the same data is used for all charts/y-axis), or switch btween various traces which are on the chart.

Note, the code for Functionality (3) is excluded this from the above code. The main problem is that I cannot get Functionality (1) & (2) to work.

I have searched extensively, all the documentation and all the stack questions. Most of these refer to multiple yaxis but with overlay='y', I do not want this solution.

I apologise if this has already been answered or is documented elsewhere, but I cannot find why my implementation will not output the required multi-yaxis charts.

Any advice, hacks, errors is really appreciated. This really is my last resort after spending what is way too many hours/nights on this problem.

Appendix 1: Input data sample
Appendix 2: Link to data (csv)
Appendix 3: Link to data (xlsx)
Appendix 4: Full Code:

import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.graph_objs as go
import pandas as pd
import datetime as dt

### Input Data_____________________________________________

# Extract
p_fx = 'AUD_NZD'
p_dir = "C:/Users/Gebruiker/Gen_Inds_"
p_file = p_dir + p_fx + ".csv"
df_0 = pd.read_csv(p_file,skiprows=1)
df_1 = pd.DataFrame(df_0.loc[df_0['AUD_NZD']=='AUD_NZD',['AUD_NZD','datetime','open','high','low','close','sma','sma.1','hma','hma.1','kama','kama.1','adx','aroonup', 'aroondown']])

# Prepare
df_1 = df_1.rename(columns={'AUD_NZD': "Pair",
                           "sma":"sma_s","sma.1":"sma_f",
                           "hma":"hma_s","hma.1":"hma_f",
                           "kama":"kama_s","kama.1":"kama_f",
                           })
df_1['datetime'] = df_1['datetime'].str.rstrip('.999989')
df_2 = df_1.astype({'datetime':'datetime64[ns]'})
df_2['date'] = pd.to_datetime(df_2['datetime'].dt.date, format='%Y-%m-%d')

# Input data
df_fx = pd.DataFrame(df_2[['date','Pair','open','high','low','close','sma_s','sma_f','hma_s','hma_f','kama_s','kama_f','adx','aroonup', 'aroondown']])
print(df_fx.Pair.value_counts())

### Figure_____________________________________________
# Data
t0101 = go.Scatter(x=df_fx.date, y=df_fx['close'],mode='lines',name='close',yaxis='y')
t0201 = go.Scatter(x=df_fx.date, y=df_fx['adx'],mode='lines',name='adx',yaxis='y2')
data = [t0101,t0201]

# Layout
layout= go.Layout(
    xaxis= dict(side= 'bottom', anchor= 'y2'),
    yaxis= dict(side= 'right'),
    yaxis2= dict(side='left'),
)

# Figure
fig = go.Figure(data=data, layout=layout)

### App_____________________________________________
app = dash.Dash()
app.layout = html.Div([
    dcc.Graph(id='chart', figure=fig)
])

### End_____________________________________________
if __name__ == '__main__':
    app.run_server()


Appendix 4: Partial solution (the stacked charts implemented in callback for Requirement #3)

    # add the relevant sub-charts / traces to the fig. 
    fig = psp.make_subplots(rows=2, cols=1)
    fig.append_trace(go.Scatter(x=df_fx.date, y=df_fx.close ,mode='lines',name='close'), 
                     row=1, col=1)
    fig.append_trace(go.Scatter(x=df_fx.date, y=df_fx.sma_s ,mode='lines',name='sma_s'), 
                     row=1, col=1)    
    fig.append_trace(go.Scatter(x=df_fx.date, y=df_fx.adx ,mode='lines',name='adx'),
                     row=2, col=1)

    fig.update_layout(height=600, title_text="Close and ADX")

Appendix 5: Solution output

1
Could you please provide some data in a text format so one could reproduce the issue? A list to an actual CSV File would be fine too. - Roy2012
Links to files added. Thanks for having a look. - Rob VdN
Rob, this description is pretty complex. Any chance to show the core issue with a simpler description/program? - halloleo
Hi, the core issue is I cannot get two charts (i.e. two y-axis) stacked on top of each other with the same x-axis. The steps I have taken are: [#1]. Define traces and specify yaxis (i.e. 'y', 'y2'); [#2]. Define layout and specify yaxis, yaxis2; [#3]. Input traces and layout into go.Figure() from steps #1 & #2 above; [#4]. Create Dash app and specfify DCC.Graph() using steps #3 above. I will add a summary of the core code above. - Rob VdN

1 Answers

0
votes

The feature you need to use is sub-plots. Here's your figure (with randomly generated data - created before you added the CSV files to the question).

# some fake data (use your CSV instead)
dates = pd.date_range(start = "2020-01-01", end = "2020-06-01", freq="1D")
close = np.random.uniform(90, 110, len(dates))
adx = np.random.uniform(190, 210, len(dates))

# important part - use sub-plots. 
fig = make_subplots(rows=2, cols=1)

# add the relevant sub-charts / traces to the fig. 
fig.append_trace(go.Scatter(x=dates, y=close ,mode='lines',name='close'), 
                 row=1, col=1)
fig.append_trace(go.Scatter(x=dates, y=adx ,mode='lines',name='adx'),
                 row=2, col=1)

fig.update_layout(height=600, title_text="Close and ADX")

The result is:

enter image description here