Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
209 views
in Technique[技术] by (71.8m points)

python - How to change colors automatically once a parameter is changed

In the following code, the color of bars changes as the threshold is changed. Instead of using the threshold and plotting the horizontal line in the code, I want to use the y parameter in the OnMouseMove function so that the user can change the location of "threshold". Then, I want the colors to be updated as the y is changed.

I think what I need is called "observer pattern" or perhaps a trick using the animation tools but not sure how to implement it. I appreciate any insight on how to do this. Thanks

%matplotlib notebook
import pandas as pd
import numpy as np
from scipy import stats
import matplotlib.colors as mcol
import matplotlib.cm as cm
import matplotlib.pyplot as plt

np.random.seed(12345)
df = pd.DataFrame([np.random.normal(335,1500,300), 
                   np.random.normal(410,900,300), 
                   np.random.normal(410,1200,300), 
                   np.random.normal(480,550,300)], 
                  index=[1,2,3,4])

fig, ax = plt.subplots()
plt.show()
bars = plt.bar(range(df.shape[0]), df.mean(axis = 1), color = 'lightslategrey')

fig = plt.gcf()
threshold=420
plt.axhline(y = threshold, color = 'grey', alpha = 0.5)

cm1 = mcol.LinearSegmentedColormap.from_list("Test",["b", "white", "purple"])
cpick = cm.ScalarMappable(cmap=cm1)
cpick.set_array([])

percentages = []
for bar in bars:
    percentage = (bar.get_height()-threshold)/bar.get_height()
    if percentage>1: percentage = 1
    if percentage<0: percentage=0
    percentages.append(percentage)

cpick.to_rgba(percentages)
bars = plt.bar(range(df.shape[0]), df.mean(axis = 1), color = cpick.to_rgba(percentages))
plt.colorbar(cpick, orientation='horizontal')

def onMouseMove(event):
    ax.lines = [ax.lines[0]]
    plt.axhline(y=event.ydata, color="k")

fig.canvas.mpl_connect('motion_notify_event', onMouseMove)

plt.xticks(range(df.shape[0]), df.index, alpha = 0.8)
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

First you should use exactly one bar plot and exactly one axhline (using more will make everything chaotic). You can set the colors of the bars via

for bar in bars:
    bar.set_color(..)

and you can update the axhline's position via line.set_ydata(position).

Now, for every mouse move event you need to update the axhline's position, calculate the percentages and apply a new colors to the bars. So those things should be done in a function, which is called every time the mouse move event is triggered. After those settings have been applied the canvas needs to be drawn for them to become visible.

Here is a complete code.

import pandas as pd
import numpy as np
import matplotlib.colors as mcol
import matplotlib.cm as cm
import matplotlib.pyplot as plt

np.random.seed(12345)
df = pd.DataFrame([np.random.normal(335,1500,300), 
                   np.random.normal(410,900,300), 
                   np.random.normal(410,1200,300), 
                   np.random.normal(480,550,300)], 
                  index=[1,2,3,4])

fig, ax = plt.subplots()

threshold=420.
bars = plt.bar(range(df.shape[0]), df.mean(axis = 1), color = 'lightslategrey')
axline = plt.axhline(y = threshold, color = 'grey', alpha = 0.5)

cm1 = mcol.LinearSegmentedColormap.from_list("Test",["b", "white", "purple"])
cpick = cm.ScalarMappable(cmap=cm1) 
cpick.set_array([])
plt.colorbar(cpick, orientation='horizontal')

def percentages(threshold):
    percentages = []
    for bar in bars:
        percentage = (bar.get_height()-threshold)/bar.get_height()
        if percentage>1: percentage = 1
        if percentage<0: percentage=0
        percentages.append(percentage)
    return percentages

def update(threshold):
    axline.set_ydata(threshold)
    perc = percentages(threshold)
    for bar, p in zip(bars, perc):
        bar.set_color(cpick.to_rgba(p))

# update once before showing
update(threshold)

def onMouseMove(event):
    if event.inaxes == ax:
        update(event.ydata)
        fig.canvas.draw_idle()

fig.canvas.mpl_connect('motion_notify_event', onMouseMove)

plt.xticks(range(df.shape[0]), df.index, alpha = 0.8)

plt.show()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...