Home > Software engineering >  How to use rangesliders feature from matplotlib in tkinter?
How to use rangesliders feature from matplotlib in tkinter?

Time:03-01

I have written a code to use the RangeSldider widget to have control over my axis range.

from tkinter import *
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import cm
from matplotlib.colors import ListedColormap
from RangeSlider.RangeSlider import RangeSliderH, RangeSliderV

root = Tk()
root.geometry("600x600")

def plot():
    x, y = np.mgrid[slice(0, 6, 1), slice(0, 6, 1)]
    z = np.arange(1,26).reshape(5,5)
    figure = Figure(figsize=(4, 4))
    ax = figure.add_subplot(111)

    col_type = cm.get_cmap('rainbow', 256)
    newcolors = col_type(np.linspace(0, 1, 1000))
    white = np.array([1, 1, 1, 1])
    newcolors[:1, :] = white
    newcmp = ListedColormap(newcolors)

    c = ax.pcolormesh(x, y, z, cmap=newcmp, edgecolor='lightgrey', linewidth=0.003)
    ax.figure.colorbar(c)

    ax.set_title('mY Title', fontweight="bold")
    ax.set_xlabel("X", fontsize=14)
    ax.set_ylabel("Y", fontsize=14)

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

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

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=5, 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=150, y=420)

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=5, 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)
button.pack()

root.mainloop()

I got a suggestion to use the range slider feature provided by matplotlib. I searched in the libraries, and used the FloatRangeSlider. But I don't know how to add the range sliders to show on the canvas and make it work and update the figure instantly.

from tkinter import *
import numpy as np
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.colors import ListedColormap

import ipywidgets as widgets

root = Tk()
root.geometry("600x600")

def plot():
    x, y = np.mgrid[slice(0, 6, 1), slice(0, 6, 1)]
    z = np.arange(1,26).reshape(5,5)
    figure = Figure(figsize=(8, 8))
    ax = figure.add_subplot(111)

    col_type = cm.get_cmap('rainbow', 256)
    newcolors = col_type(np.linspace(0, 1, 1000))
    white = np.array([1, 1, 1, 1])
    newcolors[:1, :] = white
    newcmp = ListedColormap(newcolors)

    c = ax.pcolormesh(x, y, z, cmap=newcmp, edgecolor='lightgrey', linewidth=0.003)
    ax.figure.colorbar(c)

    ax.set_title('mY Title', fontweight="bold")
    ax.set_xlabel("X", fontsize=14)
    ax.set_ylabel("Y", fontsize=14)

    sliderH = widgets.FloatRangeSlider(value=(0, 5), min=0, max=5, step=1, orientation='horizontal')
    sliderV = widgets.FloatRangeSlider(value=(0, 5), min=0, max=5, step=1, orientation='vertical')

    canvas = FigureCanvasTkAgg(figure, root)
    canvas.get_tk_widget().pack()

    def update():
        x, y = np.mgrid[slice(sliderH.value[0], sliderH.value[1], 1), slice(sliderV.value[0], sliderV.value[1], 1)]
        figure.canvas.draw()

    sliderH.observe(update, names='value')
    sliderV.observe(update, names='value')
    display(sliderH)
    display(sliderV)

button = Button(root, text="Plot", command=plot)
button.pack()

root.mainloop()

CodePudding user response:

Unless I misunderstood something, You were not using RangeSLider of matplotlib, but ipywidgets. That library is used for Jupyter notebook.

Here is implementation using RangeSLider of matplotlib with live axis range update:

from tkinter import *

import matplotlib
import numpy as np

matplotlib.use('TkAgg')
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import cm
from matplotlib.colors import ListedColormap

import matplotlib.widgets as widgets

root = Tk()
root.geometry("600x600")

x, y = np.mgrid[slice(0, 6, 1), slice(0, 6, 1)]
z = np.arange(1, 26).reshape(5, 5)
figure = Figure(figsize=(8, 8))

# Make figure a bit wider and taller
figure.subplots_adjust(bottom=0.2)
figure.subplots_adjust(left=0.2)
ax = figure.add_subplot(111)

col_type = cm.get_cmap('rainbow', 256)
newcolors = col_type(np.linspace(0, 1, 1000))
white = np.array([1, 1, 1, 1])
newcolors[:1, :] = white
newcmp = ListedColormap(newcolors)

c = ax.pcolormesh(x, y, z, cmap=newcmp, edgecolor='lightgrey', linewidth=0.003)
ax.figure.colorbar(c)

ax.set_title('mY Title', fontweight="bold")
ax.set_xlabel("X", fontsize=14)
ax.set_ylabel("Y", fontsize=14)

# Create X slider
slider_ax = figure.add_axes([0.2, 0.05, 0.6, 0.03])
sliderH = widgets.RangeSlider(slider_ax, "Val", valmin=0, valmax=5, valstep=1, valinit=(0, 5))
# Create Y slider
slider_ay = figure.add_axes([0.05, 0.25, 0.03, 0.6])
sliderV = widgets.RangeSlider(slider_ay, "Val", valmin=0, valmax=5, valstep=1, valinit=(0, 5), orientation='vertical')


def set_x_range(value):
    ax.set_xlim(xmin=value[0], xmax=value[1])


def set_y_range(value):
    ax.set_ylim(ymin=value[0], ymax=value[1])


sliderH.on_changed(set_x_range)
sliderV.on_changed(set_y_range)

canvas = FigureCanvasTkAgg(figure, root)
canvas.draw()

button = Button(root, text="Plot", command=canvas.get_tk_widget().pack)
button.pack()

root.mainloop()

This is how it looks:

plot

I had a small issue with vertical slider, that buttons were still going horizontal. Maybe it was only my environment or maybe it's matplotlib bug.
You can solve it by using both sliders in horizontal orientation.

  • Related