0

I want to have control over the ranges of the axis using the RangeSliders, and when I set the left/right or up/down sliders the figure updates automatically.

I initially wrote a code to do this task using a button.

import tkinter as tk
from tkinter import *
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from RangeSlider.RangeSlider import RangeSliderH, RangeSliderV

root = Tk()

root.geometry("700x500")

def plot():
    figure = Figure(figsize=(5, 4))
    ax = figure.add_subplot(111)

    ax.set_xlim(rs1.getValues())
    ax.set_ylim(rs2.getValues())

    canvas = FigureCanvasTkAgg(figure, root)
    canvas.get_tk_widget().place(x=120, y=0)
    figure.patch.set_facecolor('#f0f0f0')

hVar1 = IntVar() # left handle variable
hVar2 = IntVar()  # right handle variable
rs1 = RangeSliderH(root, [hVar1, hVar2], Width=230, Height=55, padX=17, min_val=0, max_val=100, font_size=12,\
                   show_value=True, digit_precision='.0f', bgColor='#f0f0f0', line_s_color='black',\
                   line_color='black', bar_color_inner='black', bar_color_outer='#f0f0f0')
rs1.place(x=250, y=400)

vVar1 = IntVar()  # top handle variable
vVar2 = IntVar()  # down handle variable
rs2 = RangeSliderV(root, [vVar1, vVar2], Width=81, Height=180, padY=11, min_val=0, max_val=100, font_size=12,\
                   show_value=True, digit_precision='.0f', bgColor='#f0f0f0', line_s_color='black',\
                   line_color='black', bar_color_inner='black', bar_color_outer='#f0f0f0')
rs2.place(x=0, y=150)

button = Button(root, text="Plot", command=plot, width=10)
button.place(x=300, y=470)

root.mainloop()

I wrote this code by getting the idea of automatic update from the link below using introduced method 3: Constantly Update Label Widgets From Entry Widgets TKinter But I cannot figure out how to make it work automatically without a button.

import tkinter as tk
from tkinter import *
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from RangeSlider.RangeSlider import RangeSliderH, RangeSliderV

root = Tk()

root.geometry("700x500")

def plot():
    figure = Figure(figsize=(5, 4))
    ax = figure.add_subplot(111)

    ax.set_xlim(rs1.getValues())
    ax.set_ylim(rs2.getValues())

    canvas = FigureCanvasTkAgg(figure, root)
    canvas.get_tk_widget().place(x=120, y=0)
    figure.patch.set_facecolor('#f0f0f0')

def auto():
    ax.set_xlim(rs1.getValues())
    ax.set_ylim(rs2.getValues())
    # call again after 100 ms
    root.after(100, auto)


hVar1 = IntVar() # left handle variable
hVar2 = IntVar()  # right handle variable
rs1 = RangeSliderH(root, [hVar1, hVar2], Width=230, Height=55, padX=17, min_val=0, max_val=100, font_size=12,\
                   show_value=True, digit_precision='.0f', bgColor='#f0f0f0', line_s_color='black',\
                   line_color='black', bar_color_inner='black', bar_color_outer='#f0f0f0')
rs1.place(x=250, y=400)


vVar1 = IntVar()  # top handle variable
vVar2 = IntVar()  # down handle variable
rs2 = RangeSliderV(root, [vVar1, vVar2], Width=81, Height=180, padY=11, min_val=0, max_val=100, font_size=12,\
                   show_value=True, digit_precision='.0f', bgColor='#f0f0f0', line_s_color='black',\
                   line_color='black', bar_color_inner='black', bar_color_outer='#f0f0f0')
rs2.place(x=0, y=150)

auto()

button = Button(root, text="Plot", command=plot, width=10)
button.place(x=300, y=470)

root.mainloop()
Mr. T
  • 11,960
  • 10
  • 32
  • 54

1 Answers1

0

The code is largely reused from your sample code. Main changes:

  • distinct functions to 1) initiate the figure plot (that returns the created figure and axis object) and 2) update the axis object
  • calling the update function with .trace_add() as outlined in the RangeSlider library

I also removed from tkinter import * because reasons

import tkinter as tk
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from RangeSlider.RangeSlider import RangeSliderH, RangeSliderV

root = tk.Tk()

root.geometry("700x500")

def plot_init():
    figure = Figure(figsize=(5, 4))
    ax = figure.add_subplot(111)    
    canvas = FigureCanvasTkAgg(figure, root)
    canvas.get_tk_widget().place(x=120, y=0)
    figure.patch.set_facecolor('#f0f0f0')
    return figure, ax

def plot_update(name, index, operation):
    ax1.set_title(f"last change: {name}")
    ax1.set_xlim(rs1.getValues())
    ax1.set_ylim(rs2.getValues())
    fig1.canvas.draw_idle()
    
hVar1 = tk.IntVar(name="horizontal slider") # left handle variable
hVar2 = tk.IntVar()  # right handle variable
rs1 = RangeSliderH(root, [hVar1, hVar2], Width=230, Height=55, padX=17, min_val=0, max_val=100, font_size=12,\
                   show_value=True, digit_precision='.0f', bgColor='#f0f0f0', line_s_color='black',\
                   line_color='black', bar_color_inner='black', bar_color_outer='#f0f0f0')
rs1.place(x=250, y=400)


vVar1 = tk.IntVar(name="vertical slider")  # top handle variable
vVar2 = tk.IntVar()  # down handle variable
rs2 = RangeSliderV(root, [vVar1, vVar2], Width=81, Height=180, padY=11, min_val=0, max_val=100, font_size=12,\
                   show_value=True, digit_precision='.0f', bgColor='#f0f0f0', line_s_color='black',\
                   line_color='black', bar_color_inner='black', bar_color_outer='#f0f0f0')
rs2.place(x=0, y=150)


hVar1.trace_add('write', plot_update)
vVar1.trace_add('write', plot_update)

fig1, ax1 = plot_init()
plot_update("None", 0, 0)

root.mainloop()

Sample output: enter image description here

The documentation of the RangeSlider library is rudimentary to non-existing, so why you only have to bind one of the two slider variables to the update function is anybody's guess. I would rather use the RangeSlider class provided by matplotlib for future support.

Mr. T
  • 11,960
  • 10
  • 32
  • 54
  • Thank you. it works well. Just for my main problem, I have a global variable. When I want to have that global variable inside `plot_init` function, it gives this error that the variable is not defined but before, it was working fine. –  Feb 28 '22 at 03:21