Non-linear Slider

Hello Dash-Community,

I created a non-linear slider, but the marks are not evenly distributed on the slider. They are somehow sitting on each other. If I use linear values, the slider is working fine. But my values are in a log scale.

It should look like this:

What do I need to do, to space the marks evenly on the slider? CSS?

Really appreciate any input to this matter. :slight_smile:

Hi @cody and welcome to the Dash community :slight_smile:

There is an example of a non-linear slider in the docs here, but there is a small bug in the example (the marks don’t appear). Below is an updated version so you can see the scale on the slider:

image

import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import dash

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

# Use the following function when accessing the value of 'my-slider'
# in callbacks to transform the output value to logarithmic
def transform_value(value):
    return 10 ** value


app.layout = html.Div([
    dcc.Slider(
        id='slider-updatemode',
        marks={i: {'label': '{}'.format(10 ** i)} for i in range(4)},
        min=0,
        max=3,
        value=2,
        step=0.01,
        updatemode='drag'
    ),
    html.Div(id='updatemode-output-container', style={'margin-top': 20})
])


@app.callback(Output('updatemode-output-container', 'children'),
              Input('slider-updatemode', 'value'))
def display_value(value):
    return 'Linear Value: {} | \
            Log Value: {:0.2f}'.format(value, transform_value(value))


if __name__ == '__main__':
    app.run_server(debug=True)

Hi @AnnMarieW Thank you so much for your reply!

Your slider marks are evenly apart since they are linearly distributed. One mark is ten times the previous one.

I need my slider to be like this, where the values are also the marks:

slider = dbc.Card([
    dbc.FormGroup([
        dbc.Label('log_scale'),
        dcc.Slider(
            id='log_scale',
            min=1,
            max=6,
            step=None,
            marks={
                1: '0.001',
                2: '0.005',
                3: '0.01',
                4: '0.05',
                5: '0.1',
                6: '0.5'
            },
            value=4
        )
    ]),

As you can see in the code, to archive an evenly distributed spacing between the marks, my values are the numbers from 1 to 6. But I need the numbers 0.001 to 0.5 like the marks as input values in callbacks.

Hi @cody
If you look at the example, the log value is calculated in the callback:

# Use the following function when accessing the value of 'my-slider'
# in callbacks to transform the output value to logarithmic
def transform_value(value):
    return 10 ** value

In your case, to get the range you are looking for, you can adjust the min and max values of the slider. For example, to get a scale from 0.001 to 1, you could use a min=-3 and max=0

Hi @AnnMarieW
I understand. But what do I do when I want to have exactly these values only: 0.001, 0.005, 0.01, 0.05, 0.1 and 0.5? Nothing in between?

Am I even supposed to use a slider for that? What do you think are better selection options for such a case? Those numbers are parameters for a function. Each of those parameters will have a different affect on a graph shown as an output.

If you really want a slider, you can set the steps so you only get the numbers you want, but for this use-case, a Dropdown or even RadioItems might work better for you.

So, I found a solution to my problem. Huge thanks to @AnnMarieW for her input. She suggested to use a function to transform the values. I wrote a function that uses a dictionary to map the slider input value to whatever value I need, but still maintaining an even spacing between the marks on the slider. Keep in mind, when the values of the slider (marks) are not linear scale (e.g. 1,3,5,7,9,…), but rather log scale or non-linear scale (e.g. 1,2,6,14,30), the slider will have the marks sitting on each other. That is because the steps are not going up by a constant factor like step=1. This problem (see OP) renders the slider pretty much useless.

dcc.Slider(
            id='non_linear_scale_slider',
            min=1,
            max=6,
            step=None,
            marks={
                1: '0.001',
                2: '0.005',
                3: '0.01',
                4: '0.05',
                5: '0.1',
                6: '0.5'
            },
            value=4
        )


# Use in a callback to transform input value of slider to arbitrary value
def transform_value(slider_value):
     int_to_scale = dict([
        (1, 0.001),
        (2, 0.005),
        (3, 0.01),
        (4, 0.05),
        (5, 0.1),
        (6, 0.5)
    ])

    return int_to_scale[slider_value]

1 Like