Search code examples
python-3.xpandasplotlyplotly-dashplotly-python

How to make binwidths wider in plotly?


I am trying to figure out how to fill the bin widths for a plotly dash dashboard. As it stands, I have a bunch of stock data in the dataset that can change the look of the charts.

When there are stock tickers with a wide X axis (strike), the data almost becomes invisible.

invisible data

Zooming in, the bins seem to only occupy ~ 10% of the available space. I am assuming this is due to them being offset, but one step at a time.

enter image description here

How can I set the binwidths to take up the whole area?

I tried using

fig.update_traces(xbins=dict(
            start = 0.0,
            end = 60,
            size = 2))

and other variations but could not get it to work.

plotly / dash code below along with dataframe sample.

import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import plotly.express as px


tickers = GEX['ticker'].unique()
pos_neg = GEX['pos_neg'].unique()

app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Dropdown(
        id="dropdown",
        options=[{"label": x, "value": x} for x in tickers],
        value=tickers[0],
        clearable=False,
    ),
    dcc.Graph(id="bar-chart", style = {'width': '90vh', 'height': '90vh'}),
])

@app.callback(
    Output("bar-chart", "figure"), 
    [Input("dropdown", "value")])
def gex_per_strike(ticker):
    mask = GEX['ticker'] == ticker
    fig = px.bar(GEX[mask], x="strike", y="net_GEX", 
                 color= 'pos_neg', 
                 barmode="group", 
                 title = ('Gamma Exposure for ' + ticker),
                 color_discrete_sequence = ['#DC143C','#7FFF00'])
    '''fig.update_traces(xbins=dict(
            start = 0.0,
            end = 60,
            size = 2))'''

    return fig

app.run_server(debug=True, use_reloader = False)

Dataframe:

import numpy as np
import pandas as pd
import random

GEX = pd.DataFrame()

GEX['strike'] = range(0,200)
GEX['pos_GEX'] = np.random.randint(0, 1000000, GEX.shape[0])
GEX['neg_GEX'] = np.random.randint(-1000000, 0, GEX.shape[0])
GEX['net_GEX'] = GEX['pos_GEX'] + GEX['neg_GEX']
GEX['pos_neg'] = GEX['net_GEX'].apply(lambda x: 1 if x > 0 else 0)
GEX['ticker'] = 'AAPL'

Solution

  • You can change the bargap argument using fig.update_layout:

    import numpy as np
    import pandas as pd
    import random
    
    GEX = pd.DataFrame()
    
    GEX['strike'] = range(0,200)
    GEX['pos_GEX'] = np.random.randint(0, 1000000, GEX.shape[0])
    GEX['neg_GEX'] = np.random.randint(-1000000, 0, GEX.shape[0])
    GEX['net_GEX'] = GEX['pos_GEX'] + GEX['neg_GEX']
    GEX['pos_neg'] = GEX['net_GEX'].apply(lambda x: 1 if x > 0 else 0)
    GEX['ticker'] = 'AAPL'
    
    import dash
    from dash import dcc
    from dash import html
    from dash.dependencies import Input, Output
    import plotly.express as px
    
    
    tickers = GEX['ticker'].unique()
    pos_neg = GEX['pos_neg'].unique()
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([
        dcc.Dropdown(
            id="dropdown",
            options=[{"label": x, "value": x} for x in tickers],
            value=tickers[0],
            clearable=False,
        ),
        dcc.Graph(id="bar-chart", style = {'width': '90vb', 'height': '90vh'}),
    ])
    
    @app.callback(
        Output("bar-chart", "figure"),
        [Input("dropdown", "value")])
    def gex_per_strike(ticker):
        mask = GEX['ticker'] == ticker
        fig = px.bar(GEX[mask], x="strike", y="net_GEX",
                     color= 'pos_neg',
                     barmode="group",
                     # width=1,
                     title = ('Gamma Exposure for ' + ticker),
                     color_discrete_sequence = ['#DC143C','#7FFF00'])
        fig.update_layout(
            bargap=0
        )
        '''fig.update_traces(xbins=dict(
                start = 0.0,
                end = 60,
                size = 2))'''
    
        return fig
    
    app.run_server(debug=True, use_reloader = False)
    

    Bar charts also have a width argument - but I guess that's not causing the issue here.