✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚾️ It's finally Baseball season! Root for the home team... & Register for our Sports Analytics Webinar!

Callback for x-axis labels

I am trying to create a Kaplan Meier graph. The effect I want to achieve can be seen here:

I need to render the risk numbers, bellow the X-axis

I have tried rendering multiple x-axis, following this example: https://plot.ly/python/multiple-axes/
but this hasn’t got me anywhere.

I have tried using a subplot, two graphs, one above the other, and hiding everything but the x-axis on the bottom one, but the values are not aligned with the x-axis of the top graph (plus too much spacing which I am not sure I will be able to remove).

Now I am looking whether there is a way to pass a callback for x-axis tick labels, so I can display the risk numbers bellow the current tick-labels using a newline character, although I can’t find a way of doing that either.

Any suggestions / examples on how to achieve the effect shown in the picture above would be greatly appreciated.

@ioannis, The idea I suggest is to define a subplot with two rows and one column explicitly, and insert the info to be displayed as annotations.

import numpy as np
import plotly.graph_objs as go

x=[k*6 for k in range(10)]
h1 = -1
h2 = -1.5

trace0=go.Scatter(x=x,
                 y= [1-k*0.05 for k in range(10)],
                 mode='lines',
                 line =dict(width=1, color='blue'),
                 name='',
                 xaxis='x',
                 yaxis='y')

trace1=go.Scatter(x=x+[None]+x,
                  y=[h1]*len(x)+[None]+[h2]*len(x),
                 mode ='text',
                 text=np.random.randint(3, 457, len(x)).tolist()+[None]+np.random.randint(6, 706, len(x)).tolist(),
                 hoverinfo='text',
                 name='',
                 xaxis='x2',
                 yaxis='y2')

annotations=[{'font': {'size': 14},
                     'showarrow': False,
                     'text': 'Title1',
                     'x': 0.5,
                     'xanchor': 'center',
                     'xref': 'paper',
                     'y': 1.0,
                     'yanchor': 'bottom',
                     'yref': 'paper'},
            {'font': {'size': 14},
                     'showarrow': False,
                     'text': 'Time (months)',
                     'x': 0.5,
                     'xanchor': 'center',
                     'xref': 'paper',
                     'y': 0.22,
                     'yanchor': 'bottom',
                     'yref': 'paper'}]

#append  here,  to annotations,  all dicts for text you want to display before setting layout['annotations']=annotations
#because after defining  an instance fw of `go.FigureWidget` you cannot append any dict to #`fw.layout.annotations`.


#set axes properties:

d_axes={'xaxis': {'anchor': 'y', 'domain': [0.0, 1.0], 'range': [-1,55], 'tick0':0, 'dtick': 6},
        'xaxis2': {'anchor': 'y2', 'domain': [0.0, 1.0], 'range':[-1,55], 'visible': False},
        'yaxis': {'anchor': 'x', 'domain': [0.4, 1.0]},
        'yaxis2': {'anchor': 'x2', 'domain': [0.0, 0.2], 'range': [h2-0.1, h1+0.1], 'visible':False}}
           

layout=go.Layout(width=700, height=450,
                         font=dict(size=12),
                         showlegend=False,
                         hovermode='closest',
                         **dict(d_axes),
                         annotations=annotations )

fw=go.FigureWidget(data=[trace0, trace1], layout=layout)
fw

It is recommended this explicit definition of subplots, because if you define
fig=plotly.tools.make_subplots()
you cannot perform fig.layout.annotations.append({}).

Following the code above you have to define all annotations, first, to avoid any illegal append to fw.layout.annotations.

All other properties of fw can be updated, eventually via fw.batch_update()

1 Like

I have been going down the subplot route, just came against a bug with Title rendering, which was meant to be fixed on 3.4.0, so I may do some digging before reporting it… I will look the annotation approach now, thank you !

from plotly import tools
import plotly.plotly as py
import plotly.graph_objs as go
from plotly.offline import init_notebook_mode, iplot

init_notebook_mode(connected=True)

bottom = go.Scatter(
    x=[2, 3, 4],
    y=[0, 0, 0],
    showlegend=False,
    opacity=0,
)
trace3 = go.Scatter(
    x=[2, 3, 4],
    y=[1000, 1100, 1200],

)

fig = tools.make_subplots(
    rows=2,
    cols=1,
    row_width=[0.2, 0.6],
    subplot_titles=['KM Graph', 'No. of patients at risk']
)

fig.append_trace(trace3, 1, 1)
fig.append_trace(bottom, 2, 1)



fig['layout'].update(height=600, width=600,
    xaxis2={
        "showgrid": False,
        "zeroline":False,
        "tickmode": "array",
        "tickvals": [2, 3, 4],
        "ticktext": ["51", "44", "20"],
        "side": "top"
    },     
    yaxis2={
        "zeroline":False,
        "showticklabels":False,
        "showline":False,
        "showgrid": False})
iplot(fig, filename='stacked-subplots')

image