0

I have my data and codes for scatter plot as below:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# define X and y
np.random.seed(10)
x = np.arange(0,100)
y = np.random.randint(0,100,100)


df = pd.DataFrame(dict(x=x, y=y))


def dist(x,y):
    p1=np.array([0,0])
    p2=np.array([100,100])
    p3=np.array([x,y])
    return abs(np.cross(p2-p1,p3-p1)/np.linalg.norm(p2-p1))

max_dist = dist(0,10)

df["within_boundary"] = df.apply(lambda row: dist(row["x"], row["y"])<=max_dist, axis=1)

fig = plt.figure(dpi=100,figsize=(8,8))
ax = fig.subplots(1)

p0 = ax.scatter(x,y,c=df["within_boundary"]) # points
p1 = ax.plot([0,100],[0,100],'-',color="red")  # middle line
p2, = ax.plot([0,90],[10,100],'--',color="black")  # upper line
p3, = ax.plot([10,100],[0,90],'--',color="black")  # lower line
plt.xticks(np.arange(0,101,10))
plt.yticks(np.arange(0,101,10))
plt.grid(True)
plt.xlim([0,100])
plt.ylim([0,100])
percentage =df['within_boundary'].sum() / len(x)
plt.figtext(0.5,0.01, f"{percentage:.1%} in Spec", ha="center", va="center", fontsize=18, bbox={"facecolor":"grey", "alpha":0.5})
plt.show() # show the window"

This I use to produce the scatter plot shown as:

enter image description here

The Tolerance region are in the +-10 and the In Spec of 17% is the number of points within the 10 region divided by the number of total points in the plot.

However I want to have a slicer that I can use to just filter on the plot to change from the 10 region to either 15, 20, 25, etc and even back to 10 and it will still automatically calculate the In Spec percentage when the region is adjusted on the slicer to 10, 15, 20, or whatever I want and also make the region lines to run from 15, 20 and so on automatically if I am having the slicer to 15, or 20 and so on.

ukanafun
  • 181
  • 5

1 Answers1

1

Matplotlib Slider Demo provides already a pretty good example.

Using your code as a basis, the following example updates the data dynamically, based on the selected tolerance, defined by the slider value.

enter image description here

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button

def dist(x,y):
    p1=np.array([0,0])
    p2=np.array([100,100])
    p3=np.array([x,y])
    return abs(np.cross(p2-p1,p3-p1)/np.linalg.norm(p2-p1))

# define X and y
np.random.seed(10)
x = np.arange(0,100)
y = np.random.randint(0,100,100)
df = pd.DataFrame(dict(x=x, y=y))

tol0 = 10 #default tolerance
max_dist = dist(0,tol0)
df["within_boundary"] = df.apply(lambda row: dist(row["x"], row["y"])<=max_dist, axis=1)

# plot definition
fig = plt.figure(dpi=100,figsize=(8,8))
ax = fig.subplots(1)
plt.subplots_adjust(bottom=0.25)
plt.xticks(np.arange(0,101,10))
plt.yticks(np.arange(0,101,10))
plt.grid(True)
plt.xlim([0,100])
plt.ylim([0,100])

# initial plotting
p0 = ax.scatter(x,y,c=df["within_boundary"]) # points
p1 = ax.plot([0,100],[0,100],'-',color="red")  # middle line
p2, = ax.plot([0,90],[10,100],'--',color="black")  # upper line
p3, = ax.plot([10,100],[0,90],'--',color="black")  # lower line

percentage = df['within_boundary'].sum() / len(x)
figtext = plt.figtext(0.5,0.01, f"{percentage:.1%} in Spec", ha="center", va="center", fontsize=18, bbox={"facecolor":"grey", "alpha":0.5})

# tolerance slider
axtol = plt.axes([0.1, 0.1, 0.8, 0.05])
stol = Slider(ax=axtol, label='Tolerance', valmin=5, valmax=50, valstep=5,valinit=tol0)
def update(val):
    # current tolerance value
    tol = stol.val

    # update data according to tolerance
    max_dist = dist(0,tol)
    df["within_boundary"] = df.apply(lambda row: dist(row["x"], row["y"])<=max_dist, axis=1)
    percentage = df['within_boundary'].sum() / len(x)
    figtext.set_text(f"{percentage:.1%} in Spec")
    p0.set_array(df["within_boundary"])
    p2.set_data([0, 100-tol], [tol,100])
    p3.set_data([tol, 100], [0,100-tol])
    fig.canvas.draw_idle()
stol.on_changed(update)

# reset button
resetax = plt.axes([0.8, 0.025, 0.1, 0.04])
button = Button(resetax, 'Reset', hovercolor='0.975')
def reset(event):
    stol.reset()
button.on_clicked(reset)


plt.show()
flyakite
  • 724
  • 3
  • 6
  • Thanks @flyakite. I am writing this in the Power BI python script. Is there a way to have the "tol0 = 10 #default tolerance" line as a slicer so I can filter the values using the slicer visual in power bi to either 10, 15, 20, etc without having to change it in the code itself? – ukanafun Oct 05 '22 at 17:32
  • @ukanafun, I am very sorry :(. I thought for a moment that "slicer" was a TypO. No, from the top of my head I have no idea how to use the slicer in this case. – flyakite Oct 07 '22 at 06:45