Matplotlib jupyter笔记本:交互式更新绘图-函数具有常量和关键字参数

Matplotlib jupyter笔记本:交互式更新绘图-函数具有常量和关键字参数,matplotlib,jupyter-notebook,python-interactive,matplotlib-widget,Matplotlib,Jupyter Notebook,Python Interactive,Matplotlib Widget,我想使用matplotlib(1.5.1)在jupyter(4.0.6)笔记本中创建一个交互式绘图。问题是,静态绘图是用一个有四个变量的函数创建的,其中两个是常量,两个是关键字参数,我想以交互方式更改关键字参数 这可能吗?如果可能,如何实现 下面的概念代码显示了生成绘图make_figure(…)的函数和生成交互式绘图的命令 如果我将关键字参数更改为变量,则会收到错误消息“interact()接受0到1个位置参数,但给出了3个” 概念代码: def make_figure(const_1, co

我想使用matplotlib(1.5.1)在jupyter(4.0.6)笔记本中创建一个交互式绘图。问题是,静态绘图是用一个有四个变量的函数创建的,其中两个是常量,两个是关键字参数,我想以交互方式更改关键字参数

这可能吗?如果可能,如何实现

下面的概念代码显示了生成绘图
make_figure(…)
的函数和生成交互式绘图的命令

如果我将关键字参数更改为变量,则会收到错误消息“interact()接受0到1个位置参数,但给出了3个”

概念代码:

def make_figure(const_1, const_2, var_1=0.4, var_2=0.8):
    b = calc_b(var_1, var_2)
    c = calc_c(b, const_1, const_2)
    fig, ax = plt.subplots()
    N, bins, patches = ax.hist(c)


interact(make_figure, 
         const_1,
         const_2,
         var_1=(0.2, 0.4, 0.05),
         var_2=(0.75, 0.95, 0.05))

添加20160325:代码示例

我试图为一个类创建一个分数直方图,这取决于分别达到1.0和4.0所需的百分比

# setup some marks
ids_perc = np.random.random(33) 
print("number of entered marks: ", ids_perc.shape)
主代码为直方图;主要功能:
get_marks

# define possible marks
marks = np.array([1.0,
                  1.3,
                  1.7,
                  2.0,
                  2.3,
                  2.7,
                  3.0,
                  3.3,
                  3.7,
                  4.0,
                  5.0])
marks_possible = marks[::-1]

def get_perc_necessary(min_perc_one,
                       min_perc_four,
                       n_marks):
    """
    calculates an equally spaced array for percentage necessary to get a mark
    """
    delta = (min_perc_one - min_perc_four)/(n_marks-2-1)
    perc_necessary_raw = np.linspace(start=min_perc_four, 
                                     stop=min_perc_one, 
                                     num=n_marks-1)
    perc_necessary = np.append([0.0], np.round(perc_necessary_raw, decimals=2)) 
    return perc_necessary


def assign_marks(n_students,
                 perc_necessary,
                 achieved_perc,
                 marks_real):
    """
    get the mark for each student (with a certain achieved percentage)
    """
    final_marks = np.empty(n_students)

    for cur_i in range(n_students):
        idx = np.argmax(np.argwhere(perc_necessary <= achieved_perc[cur_i]))
        final_marks[cur_i] = marks_real[idx]

    return final_marks


def get_marks(achieved_perc = ids_perc,
              marks_real = marks_possible,                    
              min_perc_four = 0.15,
              min_perc_one = 0.85):

    n_marks = marks.shape[0]
#     print("n_marks: ", n_marks)
    n_students = achieved_perc.shape[0]
#     print("n_students: ", n_students)

    # -----------------------------
    # linear step between each mark
    perc_necessary = get_perc_necessary(min_perc_one,
                                        min_perc_four,
                                        n_marks)

    # test query: there need to be as many percentages as marks
    if perc_necessary.shape[0] != marks_real.shape[0]:
        print("the number of marks has to be equal the number of boundaries")
        raise Exception

    # ------------
    # assign marks 
    final_marks = assign_marks(n_students,
                               perc_necessary,
                               achieved_perc,
                               marks_real)    

    # ------------
    # create table
    fig, ax = plt.subplots()
    N, bins, patches = ax.hist(final_marks, 
                               align='mid', 
                               bins=np.append(marks,6.)) # bins=marks
    ax.xaxis.set_major_formatter(FormatStrFormatter('%0.1f'))
    bin_centers = 0.5 * np.diff(bins) + bins[:-1]
    ax.set_xticks(bin_centers)
    ax.set_xticklabels( marks )
    ax.set_xlabel("mark")
    ax.set_ylabel("number of marks")
    ax.set_ylim(0.0, 6.0)
    plt.grid(True)
我得到了错误

ValueError: array([ 0.22366653,  0.74206953,  0.47501716,  0.56536227,  0.54792759,
    0.60288287,  0.68548973,  0.576935  ,  0.84582243,  0.40709693,
    0.78600622,  0.2692508 ,  0.62524819,  0.62204851,  0.5421716 ,
    0.71836192,  0.97194698,  0.4054752 ,  0.2185643 ,  0.11786751,
    0.57947848,  0.88659768,  0.38803576,  0.66617254,  0.77663263,
    0.94364543,  0.23021637,  0.30899724,  0.08695842,  0.50296694,
    0.8164095 ,  0.77892531,  0.5542163 ]) cannot be transformed to a Widget

查看变量
ids\u perc
时为什么会出现此错误?

您需要在
interact()
中显式分配变量。例如,像这样:

const_1 = 1

interact(make_figure, 
         const_1=const_1,
         const_2=2,
         var_1=(0.2, 0.4, 0.05),
         var_2=(0.75, 0.95, 0.05))
或者(如果可能的话)更改
make_figure
的签名,将这些变量转换为关键字参数,这样可以避免显式传递它们:

def make_figure(const_1=1, const_2=2, var_1=0.4, var_2=0.8):
    ....

interact(make_figure, 
         var_1=(0.2, 0.4, 0.05),
         var_2=(0.75, 0.95, 0.05))
以下是您可以尝试的MCWE:

def calc_b(v1, v2):
    return v1 + v2

def calc_c(v1, v2, v3):
    return [v1, v2, v3]

def make_figure(const_1=1, const_2=2, var_1=0.4, var_2=0.8):
    b = calc_b(var_1, var_2)
    c = calc_c(b, const_1, const_2)
    fig, ax = plt.subplots()
    N, bins, patches = ax.hist(c)

interact(make_figure, 
         var_1=(0.2, 0.4, 0.05),
         var_2=(0.75, 0.95, 0.05));
这运行时没有任何错误

在您添加的20160325上:

传递给interact的每个参数都必须由以下任一参数表示(稍微简化):

  • 滑块(用于元组,表示(最小值、最大值)和标量数)
  • 选择框(用于字符串和字典列表)
  • 复选框(适用于布尔型)
  • 输入框(用于字符串)
您正在传递(通过在
get_标记中隐式地将两个参数定义为
np.array
)。 因此,
interact
不知道如何在滑块上表示它,hense错误

您至少有两种选择:

1) 更改
get_marks
的签名,以使其采用
交互
将取消接受的参数(参见上面的项目符号列表)

2) 制作另一个包装器函数,该函数将接受
交互的
取消接受的参数,但在
将这些参数转换为
获取标记
所需的任何参数后,将调用
获取标记

所以只要再多走一步,你就完成了

更新

这是你的代码和包装,为我工作。 请注意,
get_marks\u interact
不需要获取
get_marks
的所有参数,我不会传递列表,因为
interact
将有问题(列表应表示字符串列表(对于下拉小部件)或
[min,max]
值列表/元组(对于滑块))


我将
make_figure
更改为在其定义中仅包含关键字参数,并且在
interact
中,我仅为要更改其值的变量定义范围(如在第二个代码块中)。现在我得到了一个错误
ValueError:数组不能转换为小部件
interactive
是否仅在调用函数中定义的matplotlib图形上自动工作?也就是说,在
make_figure
(比如
b
c
)中计算各种各样的东西并不重要。我添加了一个最小的示例。您当前执行的
make_figure
每次在
interact
中更改参数时都会创建新的图形。所以,除非你提供了一个可复制的例子来说明试图调试的问题,否则这只是一个猜测游戏。然而,我仍然坚持我原来的问题。因此,我添加了一个稍长的示例,包括错误消息。当我真的想与图形交互时,为什么在查看变量时出现此错误?我已更新了答案以帮助您解决此错误。感谢您的努力。但是:如果我选择选项1,并查看您的项目符号列表,我可以看到唯一的选项是将我的numpy数组放入字典(也就是说常量的字典)。如果我这样做,我会得到
ValueError:包含多个元素的数组的真值是不明确的。使用a.any()或a.all()
。我不确定这是从哪里来的,因为唯一的查询是
assign\u marks
中的
np.argwhere
语句与
np.argmax()
组合,并且没有布尔查询
get_marks()
在使用字典但不使用interact的情况下仍然可以正常运行。
def calc_b(v1, v2):
    return v1 + v2

def calc_c(v1, v2, v3):
    return [v1, v2, v3]

def make_figure(const_1=1, const_2=2, var_1=0.4, var_2=0.8):
    b = calc_b(var_1, var_2)
    c = calc_c(b, const_1, const_2)
    fig, ax = plt.subplots()
    N, bins, patches = ax.hist(c)

interact(make_figure, 
         var_1=(0.2, 0.4, 0.05),
         var_2=(0.75, 0.95, 0.05));
def get_marks(min_perc_four = 0.15,
              min_perc_one = 0.85,
              marks=marks_possible,
              ach_per=ids_perc):

    marks_real = marks #  [0]
    achieved_perc = ach_per #  [0]

    n_marks = marks_real.shape[0]
    print("n_marks: ", n_marks)
    n_students = achieved_perc.shape[0]
    print("n_students: ", n_students)

    # -----------------------------
    # linear step between each mark
    perc_necessary = get_perc_necessary(min_perc_one,
                                        min_perc_four,
                                        n_marks)

    # test query: there need to be as many percentages as marks
    if perc_necessary.shape[0] != marks_real.shape[0]:
        print("the number of marks has to be equal the number of boundaries")
        raise Exception

    # ------------
    # assign marks 
    final_marks = assign_marks(n_students,
                               perc_necessary,
                               achieved_perc,
                               marks_real)

    # ------------
    # create table
    fig, ax = plt.subplots()
    N, bins, patches = ax.hist(final_marks, 
                               align='mid', 
                               bins=np.sort(np.append(marks, 6.))) # bins=marks
    ax.xaxis.set_major_formatter(FormatStrFormatter('%0.1f'))
    bin_centers = 0.5 * np.diff(bins) + bins[:-1]
    ax.set_xticks(bin_centers)
    ax.set_xticklabels( marks )
    ax.set_xlabel("mark")
    ax.set_ylabel("number of marks")
    ax.set_ylim(0.0, 6.0)
    plt.grid(True)

def get_marks_interact(min_perc_four = 0.15, 
                       min_perc_one = 0.85,):
    return get_marks(min_perc_four, min_perc_one)

interact(get_marks_wrapper, 
         min_perc_four=(0.2, 0.4, 0.05),
         min_perc_one=(0.75, 0.95, 0.05));