2012-12-01 13 views
10

Używam suwaków matplotlib, podobnych do this demo. Suwaki używają obecnie 2 miejsc po przecinku i "czują" dość ciągły (choć muszą być dyskretne na pewnym poziomie). Czy mogę zdecydować, na jakim poziomie są dyskretne? Integer kroki? Kroki o wielkości 0,1? 0,5? Mój google-fu mnie zawiódł.Czy mogę uczynić suwaki matplotlib bardziej dyskretnymi?

+0

mogę zmienić wyświetlacz do liczb całkowitych z: valfmt = '% 1.0f' ale to nie zmienia wyjście. Obecnie zamierzam wprowadzić gdzieś zaokrąglenie, ale wydaje się, że powinno to być właściwością suwaka. –

+1

Szybko zorientowałem się, że mogę zaokrąglić() wejście wewnątrz funkcji, którą aktualizuje suwak, a także wyświetlać tylko poprawną liczbę miejsc dziesiętnych. Ale jeśli chcę zaokrąglić do 1/2 rundy, nie mogę sprawić, żeby wyświetlacz pasował do wartości (nadal będzie wskazywał dokładny do 0,1). –

+0

Wystarczy ustawić wartość wyświetlaną za każdym razem. Tak długo, jak jesteś w porządku, nie "czujesz" się jak dyskretne wartości (np. Pasek nadal będzie się płynnie przesuwał), nadal możesz sprawić, że wyświetlacz będzie odzwierciedlał dyskretne wartości. (Dodanie przykładu w niewielkiej ilości ...) –

Odpowiedz

22

Jeśli chcesz tylko wartości całkowite, wystarczy przejść w approriate valfmt podczas tworzenia suwak (np valfmt='%0.0f')

Jednak jeśli chcesz invervals nie całkowitą, będziesz musiał ręcznie ustawić wartość tekstową za każdym razem. Nawet jeśli to zrobisz, suwak będzie nadal działał płynnie i nie będzie "czuł się" jak dyskretne interwały.

Oto przykład:

import matplotlib.pyplot as plt 
import numpy as np 
from matplotlib.widgets import Slider 

class ChangingPlot(object): 
    def __init__(self): 
     self.inc = 0.5 

     self.fig, self.ax = plt.subplots() 
     self.sliderax = self.fig.add_axes([0.2, 0.02, 0.6, 0.03], 
              axisbg='yellow') 

     self.slider = Slider(self.sliderax, 'Value', 0, 10, valinit=self.inc) 
     self.slider.on_changed(self.update) 
     self.slider.drawon = False 

     x = np.arange(0, 10.5, self.inc) 
     self.ax.plot(x, x, 'ro') 
     self.dot, = self.ax.plot(self.inc, self.inc, 'bo', markersize=18) 

    def update(self, value): 
     value = int(value/self.inc) * self.inc 
     self.dot.set_data([[value],[value]]) 
     self.slider.valtext.set_text('{}'.format(value)) 
     self.fig.canvas.draw() 

    def show(self): 
     plt.show() 

p = ChangingPlot() 
p.show() 

Jeśli chciał zrobić suwak „czuć” zupełnie jak wartości dyskretnych, można podklasy matplotlib.widgets.Slider. Efekt kluczem jest kontrolowany przez Slider.set_val

W takim przypadku, można by zrobić coś takiego:

class DiscreteSlider(Slider): 
    """A matplotlib slider widget with discrete steps.""" 
    def __init__(self, *args, **kwargs): 
     """Identical to Slider.__init__, except for the "increment" kwarg. 
     "increment" specifies the step size that the slider will be discritized 
     to.""" 
     self.inc = kwargs.pop('increment', 0.5) 
     Slider.__init__(self, *args, **kwargs) 

    def set_val(self, val): 
     discrete_val = int(val/self.inc) * self.inc 
     # We can't just call Slider.set_val(self, discrete_val), because this 
     # will prevent the slider from updating properly (it will get stuck at 
     # the first step and not "slide"). Instead, we'll keep track of the 
     # the continuous value as self.val and pass in the discrete value to 
     # everything else. 
     xy = self.poly.xy 
     xy[2] = discrete_val, 1 
     xy[3] = discrete_val, 0 
     self.poly.xy = xy 
     self.valtext.set_text(self.valfmt % discrete_val) 
     if self.drawon: 
      self.ax.figure.canvas.draw() 
     self.val = val 
     if not self.eventson: 
      return 
     for cid, func in self.observers.iteritems(): 
      func(discrete_val) 

I jako przykład pełnego wykorzystania go:

import matplotlib.pyplot as plt 
import numpy as np 
from matplotlib.widgets import Slider 

class ChangingPlot(object): 
    def __init__(self): 
     self.inc = 0.5 

     self.fig, self.ax = plt.subplots() 
     self.sliderax = self.fig.add_axes([0.2, 0.02, 0.6, 0.03], 
              axisbg='yellow') 

     self.slider = DiscreteSlider(self.sliderax, 'Value', 0, 10, 
            increment=self.inc, valinit=self.inc) 
     self.slider.on_changed(self.update) 

     x = np.arange(0, 10.5, self.inc) 
     self.ax.plot(x, x, 'ro') 
     self.dot, = self.ax.plot(self.inc, self.inc, 'bo', markersize=18) 

    def update(self, value): 
     self.dot.set_data([[value],[value]]) 
     self.fig.canvas.draw() 

    def show(self): 
     plt.show() 

class DiscreteSlider(Slider): 
    """A matplotlib slider widget with discrete steps.""" 
    def __init__(self, *args, **kwargs): 
     """Identical to Slider.__init__, except for the "increment" kwarg. 
     "increment" specifies the step size that the slider will be discritized 
     to.""" 
     self.inc = kwargs.pop('increment', 0.5) 
     Slider.__init__(self, *args, **kwargs) 

    def set_val(self, val): 
     discrete_val = int(val/self.inc) * self.inc 
     # We can't just call Slider.set_val(self, discrete_val), because this 
     # will prevent the slider from updating properly (it will get stuck at 
     # the first step and not "slide"). Instead, we'll keep track of the 
     # the continuous value as self.val and pass in the discrete value to 
     # everything else. 
     xy = self.poly.xy 
     xy[2] = discrete_val, 1 
     xy[3] = discrete_val, 0 
     self.poly.xy = xy 
     self.valtext.set_text(self.valfmt % discrete_val) 
     if self.drawon: 
      self.ax.figure.canvas.draw() 
     self.val = val 
     if not self.eventson: 
      return 
     for cid, func in self.observers.iteritems(): 
      func(discrete_val) 


p = ChangingPlot() 
p.show() 

enter image description here

+0

"+1", "dziękuję", przepraszam chłopaki , nie mogłem się powstrzymać. – roadrunner66

0

Jeśli nie chcesz podklasy Slider, wybrałem kilka wierszy odpowiedzi @Joe Kington, aby osiągnąć dyskretyzację w ramach funkcji callback jonowy:

sldr = Slider(ax,'name',0.,5.,valinit=0.,valfmt="%i") 
sldr.on_changed(partial(set_slider,sldr)) 

, a następnie:

def set_slider(s,val): 
    s.val = round(val) 
    s.poly.xy[2] = s.val,1 
    s.poly.xy[3] = s.val,0 
    s.valtext.set_text(s.valfmt % s.val) 
Powiązane problemy