HighwayJohn
HighwayJohn

Reputation: 921

Logarithmic slider with matplotlib

I just implemented a slider in my plot which works great. (I used this example: http://matplotlib.org/examples/widgets/slider_demo.html) Now my question is if it is possible to make the slider logarithmic. My values range between 0 and 1 and I want to make changes from 0.01 to 0.02 and so on but also from 0.01 to 0.5. That is why I think a logarithmic scale would be nice. Also if this isn't doable with a slider do you then have other ideas how to implement this?

Upvotes: 6

Views: 3598

Answers (3)

Bill
Bill

Reputation: 11613

Building on the answer by @NilsWerner, this answer, and this answer, here is a log slider for the case where you want to only allow a discrete set of values shown as tick labels. I find this is useful in the case of a log slider.

The values are pre-specified. In this example, my variable is named 'R'.

R_value = 0.5

ax_R = plt.axes([0.25, 0.15, 0.65, 0.03])
R_values = [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1.0, 2.0, 5.0, 10.0]
R_values = np.array(sorted(set(R_values))
slider_values = np.log10(R_values)
valinit = slider_values[(np.abs(R_values - R_value)).argmin()]  # snap to nearest
slider_R_log = Slider(
    ax_R, 'R',
    slider_values[0], slider_values[-1], 
    valinit=valinit,
    valstep=slider_values
)
value_formatter = lambda x: np.format_float_positional(
    x, precision=1, unique=False, 
    fractional=False, trim='k'
)
ax_R.add_artist(ax_R.xaxis)
ax_R.set_xticks(slider_values)
ax_R.set_xticklabels([value_formatter(x) for x in R_values])

def update(val):
    R_value = 10 ** val
    val_str = value_formatter(R_value)
    slider_R_log.valtext.set_text(val_str)

slider_R_log.on_changed(update)

It looks like this: Screenshot of a horizontal slider with tick labels

I can't believe this is so difficult...

Upvotes: 1

Antoine
Antoine

Reputation: 39

I know it's been few years but I think it still is useful. The previous answer is simple and straightforward but can be a problem with the inital values not correctly displayed for example. You can directly create a log slider by creating a new class inheriting from the matplotlib slider and edit the function that set the value like so :

from matplotlib.widgets import Slider


class Sliderlog(Slider):

"""Logarithmic slider.

    Takes in every method and function of the matplotlib's slider.

    Set slider to *val* visually so the slider still is lineat but display 10**val next to the slider.

    Return 10**val to the update function (func)"""

    def set_val(self, val):

        xy = self.poly.xy
        if self.orientation == 'vertical':
            xy[1] = 0, val
            xy[2] = 1, val
        else:
            xy[2] = val, 1
            xy[3] = val, 0
        self.poly.xy = xy
        self.valtext.set_text(self.valfmt % 10**val)   # Modified to display 10**val instead of val
        if self.drawon:
            self.ax.figure.canvas.draw_idle()
        self.val = val
        if not self.eventson:
            return
        for cid, func in self.observers.items():
                func(10**val)

You use it the same way you use the slider but instead of call :

    Slider(ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', closedmin=True, closedmax=True, slidermin=None, slidermax=None, dragging=True, valstep=None, orientation='horizontal')

Just call :

    Sliderlog(ax, label, valmin, valmax, valinit=0.5, valfmt='%1.2f', closedmin=True, closedmax=True, slidermin=None, slidermax=None, dragging=True, valstep=None, orientation='horizontal',

Be careful, if you want to have 10^3 as initial value you have to pass in valinit=3 not 10**3. Same for valmax and valmin. You can use log10(desired_value) if you can not easily type it.

Upvotes: 3

Nils Werner
Nils Werner

Reputation: 36765

You can simply np.log() the value of the slider. However then the label next to it would be incorrect. You need to manually set the text of valtext of the slider to the log-value:

def update(val):
    amp = np.log(slider.val)
    slider.valtext.set_text(amp)

Upvotes: 6

Related Questions