Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Pandas 标记大小/带窗口大小的alpha缩放/放大打印/分散_Pandas_Matplotlib - Fatal编程技术网

Pandas 标记大小/带窗口大小的alpha缩放/放大打印/分散

Pandas 标记大小/带窗口大小的alpha缩放/放大打印/分散,pandas,matplotlib,Pandas,Matplotlib,在探索xy图表上具有多个点的数据集时,我可以调整alpha和/或标记大小,以提供点最密集聚集位置的快速视觉印象。但是,当我放大或放大窗口时,需要使用不同的alpha和/或标记大小来提供相同的视觉效果 当我扩大窗口或放大数据时,如何使alpha值和/或标记大小增加?我在想,如果我将窗口面积加倍,我可以将标记大小加倍,和/或取alpha的平方根;与之相反的是缩放 请注意,所有点都具有相同的大小和alpha。理想情况下,该解决方案可以与plot一起使用,但如果只能使用分散处理,则也会很有帮助。您可以通

在探索xy图表上具有多个点的数据集时,我可以调整alpha和/或标记大小,以提供点最密集聚集位置的快速视觉印象。但是,当我放大或放大窗口时,需要使用不同的alpha和/或标记大小来提供相同的视觉效果

当我扩大窗口或放大数据时,如何使alpha值和/或标记大小增加?我在想,如果我将窗口面积加倍,我可以将标记大小加倍,和/或取alpha的平方根;与之相反的是缩放


请注意,所有点都具有相同的大小和alpha。理想情况下,该解决方案可以与plot一起使用,但如果只能使用分散处理,则也会很有帮助。

您可以通过matplotlib事件处理实现所需的功能。您必须分别捕获缩放和调整事件大小。同时考虑两者有点棘手,但并非不可能。下面是一个具有两个子图的示例,左侧为直线图,右侧为散点图。图形fig_因子的缩放因子和大小调整都根据图形大小和x和y限制中的比例因子重新缩放点。由于定义了两个极限-一个用于x方向,一个用于y方向,我在这里使用了两个因素的各自最小值。如果希望使用更大的因子进行缩放,请在两个事件函数中将“最小值”更改为“最大值”

from matplotlib import pyplot as plt
import numpy as np

fig, axes = plt.subplots(nrows=1, ncols = 2)
ax1,ax2 = axes
fig_width = fig.get_figwidth()
fig_height = fig.get_figheight()
fig_factor = 1.0

##saving some values
xlim = dict()
ylim = dict()
lines = dict()
line_sizes = dict()
paths = dict()
point_sizes = dict()

## a line plot
x1 = np.linspace(0,np.pi,30)
y1 = np.sin(x1)

lines[ax1] = ax1.plot(x1, y1, 'ro', markersize = 3, alpha = 0.8)
xlim[ax1] = ax1.get_xlim()
ylim[ax1] = ax1.get_ylim()
line_sizes[ax1] = [line.get_markersize() for line in lines[ax1]]


## a scatter plot
x2 = np.random.normal(1,1,30)
y2 = np.random.normal(1,1,30)

paths[ax2] = ax2.scatter(x2,y2, c = 'b', s = 20, alpha = 0.6)
point_sizes[ax2] = paths[ax2].get_sizes()

xlim[ax2] = ax2.get_xlim()
ylim[ax2] = ax2.get_ylim()


def on_resize(event):
    global fig_factor

    w = fig.get_figwidth()
    h = fig.get_figheight()

    fig_factor = min(w/fig_width,h/fig_height)

    for ax in axes:
        lim_change(ax)


def lim_change(ax):
    lx = ax.get_xlim()
    ly = ax.get_ylim()

    factor = min(
        (xlim[ax][1]-xlim[ax][0])/(lx[1]-lx[0]),
        (ylim[ax][1]-ylim[ax][0])/(ly[1]-ly[0])
    )

    try:
        for line,size in zip(lines[ax],line_sizes[ax]):
            line.set_markersize(size*factor*fig_factor)
    except KeyError:
        pass


    try:
        paths[ax].set_sizes([s*factor*fig_factor for s in point_sizes[ax]])
    except KeyError:
        pass

fig.canvas.mpl_connect('resize_event', on_resize)
for ax in axes:
    ax.callbacks.connect('xlim_changed', lim_change)
    ax.callbacks.connect('ylim_changed', lim_change)
plt.show()
该代码已经在Pyton 2.7和3.6中使用matplotlib 2.1.1进行了测试

编辑

受以下评论和建议的启发,我创建了另一个解决方案。这里的主要思想是只使用一种类型的事件,即draw_事件。起初,缩放时绘图没有正确更新。同样,链接答案中的ax.draw_artist和fig.canvas.draw_idle没有真正解决问题,但是,这可能是特定于平台/后端的。取而代之的是,每当比例改变时,我都会对fig.canvas.draw添加一个额外的调用,if语句会阻止无限循环

此外,为了避免使用所有全局变量,我将所有内容都封装到一个名为MarkerUpdater的类中。每个Axis实例都可以单独注册到MarkerUpdater实例,因此您也可以在一个图中拥有多个子图,其中一些子图已更新,一些子图未更新。我还修复了另一个错误,即散点图中的点缩放错误-它们应该是二次缩放,而不是线性缩放

最后,由于上一个解决方案中缺少了它,我还为标记的alpha值添加了更新。这并不像标记大小那样直接,因为alpha值不能大于1.0。因此,在我的实现中,alpha值只能从原始值减少。在这里,我实现了它,当图形大小减小时,alpha减小。请注意,如果未向plot命令提供alpha值,则美工人员将不存储alpha值。在这种情况下,自动alpha调谐关闭

使用features关键字定义轴时应更新的内容-有关如何使用MarkerUpdater的示例,请参见下面的if _uname _uuu=='_uu main uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

编辑2

正如@ImportanceOfBeingErnest所指出的,在使用TkAgg后端时,我的答案存在无限递归的问题,而且很明显,在缩放时图形没有正确刷新的问题,我无法验证,因此可能这取决于实现。移除fig.canvas.draw并在轴实例上的循环中添加ax.draw\u artistax修复了此问题

编辑3

我更新了代码,以修复一个正在进行的问题,即图形在draw_事件中没有正确更新。修正是从这个答案,但修改也适用于几个数字

就如何获得因子的解释而言,MarkerUpdater实例包含一个dict,该dict为每个轴实例存储图形尺寸和添加add_ax时的轴限制。在draw_事件(例如,当调整图形大小或用户放大数据时触发)时,检索图形大小和轴限制的新当前值,并计算和存储缩放因子,以便放大和增加图形大小使标记变大。因为x和y维度可能以不同的速率变化,所以我使用min从两个计算因子中选择一个,并始终根据图形的原始大小进行缩放

如果希望使用不同的函数缩放alpha,可以轻松更改调整alpha值的线条。例如,如果你想要幂律而不是线性递减,你可以写path.set_alphaalpha*facA**n,其中n是幂

from matplotlib import pyplot as plt
import numpy as np

##plt.switch_backend('TkAgg')
class MarkerUpdater:
    def __init__(self):
        ##for storing information about Figures and Axes
        self.figs = {}

        ##for storing timers
        self.timer_dict = {}

    def add_ax(self, ax, features=[]):
        ax_dict = self.figs.setdefault(ax.figure,dict())
        ax_dict[ax] = {
            'xlim' : ax.get_xlim(),
            'ylim' : ax.get_ylim(),
            'figw' : ax.figure.get_figwidth(),
            'figh' : ax.figure.get_figheight(),
            'scale_s' : 1.0,
            'scale_a' : 1.0,
            'features' : [features] if isinstance(features,str) else features,
        }
        ax.figure.canvas.mpl_connect('draw_event', self.update_axes)

    def update_axes(self, event):

        for fig,axes in self.figs.items():
            if fig is event.canvas.figure:

                for ax, args in axes.items():
                    ##make sure the figure is re-drawn
                    update = True

                    fw = fig.get_figwidth()
                    fh = fig.get_figheight()
                    fac1 = min(fw/args['figw'], fh/args['figh'])


                    xl = ax.get_xlim()
                    yl = ax.get_ylim()
                    fac2 = min(
                        abs(args['xlim'][1]-args['xlim'][0])/abs(xl[1]-xl[0]),
                        abs(args['ylim'][1]-args['ylim'][0])/abs(yl[1]-yl[0])
                    )

                    ##factor for marker size
                    facS = (fac1*fac2)/args['scale_s']

                    ##factor for alpha -- limited to values smaller 1.0
                    facA = min(1.0,fac1*fac2)/args['scale_a']

                    ##updating the artists
                    if facS != 1.0:
                        for line in ax.lines:
                            if 'size' in args['features']:
                                line.set_markersize(line.get_markersize()*facS)

                            if 'alpha' in args['features']:
                                alpha = line.get_alpha()
                                if alpha is not None:
                                    line.set_alpha(alpha*facA)


                        for path in ax.collections:
                            if 'size' in args['features']:
                                path.set_sizes([s*facS**2 for s in path.get_sizes()])

                            if 'alpha' in args['features']:
                                alpha = path.get_alpha()
                                if alpha is not None:
                                    path.set_alpha(alpha*facA)

                        args['scale_s'] *= facS
                        args['scale_a'] *= facA

                self._redraw_later(fig)



    def _redraw_later(self, fig):
        timer = fig.canvas.new_timer(interval=10)
        timer.single_shot = True
        timer.add_callback(lambda : fig.canvas.draw_idle())
        timer.start()

        ##stopping previous timer
        if fig in self.timer_dict:
            self.timer_dict[fig].stop()

        ##storing a reference to prevent garbage collection
        self.timer_dict[fig] = timer

if __name__ == '__main__':
    my_updater = MarkerUpdater()

    ##setting up the figure
    fig, axes = plt.subplots(nrows = 2, ncols =2)#, figsize=(1,1))
    ax1,ax2,ax3,ax4 = axes.flatten()

    ## a line plot
    x1 = np.linspace(0,np.pi,30)
    y1 = np.sin(x1)
    ax1.plot(x1, y1, 'ro', markersize = 10, alpha = 0.8)
    ax3.plot(x1, y1, 'ro', markersize = 10, alpha = 1)

    ## a scatter plot
    x2 = np.random.normal(1,1,30)
    y2 = np.random.normal(1,1,30)
    ax2.scatter(x2,y2, c = 'b', s = 100, alpha = 0.6)

    ## scatter and line plot
    ax4.scatter(x2,y2, c = 'b', s = 100, alpha = 0.6)
    ax4.plot([0,0.5,1],[0,0.5,1],'ro', markersize = 10) ##note: no alpha value!

    ##setting up the updater
    my_updater.add_ax(ax1, ['size'])  ##line plot, only marker size
    my_updater.add_ax(ax2, ['size'])  ##scatter plot, only marker size
    my_updater.add_ax(ax3, ['alpha']) ##line plot, only alpha
    my_updater.add_ax(ax4, ['size', 'alpha']) ##scatter plot, marker size and alpha

    plt.show()

通过matplotlib事件处理,您可以实现所需的功能。您必须分别捕获缩放和调整事件大小。同时考虑两者有点棘手,但是 并非不可能。下面是一个具有两个子图的示例,左侧为直线图,右侧为散点图。图形fig_因子的缩放因子和大小调整都根据图形大小和x和y限制中的比例因子重新缩放点。由于定义了两个极限-一个用于x方向,一个用于y方向,我在这里使用了两个因素的各自最小值。如果希望使用更大的因子进行缩放,请在两个事件函数中将“最小值”更改为“最大值”

from matplotlib import pyplot as plt
import numpy as np

fig, axes = plt.subplots(nrows=1, ncols = 2)
ax1,ax2 = axes
fig_width = fig.get_figwidth()
fig_height = fig.get_figheight()
fig_factor = 1.0

##saving some values
xlim = dict()
ylim = dict()
lines = dict()
line_sizes = dict()
paths = dict()
point_sizes = dict()

## a line plot
x1 = np.linspace(0,np.pi,30)
y1 = np.sin(x1)

lines[ax1] = ax1.plot(x1, y1, 'ro', markersize = 3, alpha = 0.8)
xlim[ax1] = ax1.get_xlim()
ylim[ax1] = ax1.get_ylim()
line_sizes[ax1] = [line.get_markersize() for line in lines[ax1]]


## a scatter plot
x2 = np.random.normal(1,1,30)
y2 = np.random.normal(1,1,30)

paths[ax2] = ax2.scatter(x2,y2, c = 'b', s = 20, alpha = 0.6)
point_sizes[ax2] = paths[ax2].get_sizes()

xlim[ax2] = ax2.get_xlim()
ylim[ax2] = ax2.get_ylim()


def on_resize(event):
    global fig_factor

    w = fig.get_figwidth()
    h = fig.get_figheight()

    fig_factor = min(w/fig_width,h/fig_height)

    for ax in axes:
        lim_change(ax)


def lim_change(ax):
    lx = ax.get_xlim()
    ly = ax.get_ylim()

    factor = min(
        (xlim[ax][1]-xlim[ax][0])/(lx[1]-lx[0]),
        (ylim[ax][1]-ylim[ax][0])/(ly[1]-ly[0])
    )

    try:
        for line,size in zip(lines[ax],line_sizes[ax]):
            line.set_markersize(size*factor*fig_factor)
    except KeyError:
        pass


    try:
        paths[ax].set_sizes([s*factor*fig_factor for s in point_sizes[ax]])
    except KeyError:
        pass

fig.canvas.mpl_connect('resize_event', on_resize)
for ax in axes:
    ax.callbacks.connect('xlim_changed', lim_change)
    ax.callbacks.connect('ylim_changed', lim_change)
plt.show()
该代码已经在Pyton 2.7和3.6中使用matplotlib 2.1.1进行了测试

编辑

受以下评论和建议的启发,我创建了另一个解决方案。这里的主要思想是只使用一种类型的事件,即draw_事件。起初,缩放时绘图没有正确更新。同样,链接答案中的ax.draw_artist和fig.canvas.draw_idle没有真正解决问题,但是,这可能是特定于平台/后端的。取而代之的是,每当比例改变时,我都会对fig.canvas.draw添加一个额外的调用,if语句会阻止无限循环

此外,为了避免使用所有全局变量,我将所有内容都封装到一个名为MarkerUpdater的类中。每个Axis实例都可以单独注册到MarkerUpdater实例,因此您也可以在一个图中拥有多个子图,其中一些子图已更新,一些子图未更新。我还修复了另一个错误,即散点图中的点缩放错误-它们应该是二次缩放,而不是线性缩放

最后,由于上一个解决方案中缺少了它,我还为标记的alpha值添加了更新。这并不像标记大小那样直接,因为alpha值不能大于1.0。因此,在我的实现中,alpha值只能从原始值减少。在这里,我实现了它,当图形大小减小时,alpha减小。请注意,如果未向plot命令提供alpha值,则美工人员将不存储alpha值。在这种情况下,自动alpha调谐关闭

使用features关键字定义轴时应更新的内容-有关如何使用MarkerUpdater的示例,请参见下面的if _uname _uuu=='_uu main uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

编辑2

正如@ImportanceOfBeingErnest所指出的,在使用TkAgg后端时,我的答案存在无限递归的问题,而且很明显,在缩放时图形没有正确刷新的问题,我无法验证,因此可能这取决于实现。移除fig.canvas.draw并在轴实例上的循环中添加ax.draw\u artistax修复了此问题

编辑3

我更新了代码,以修复一个正在进行的问题,即图形在draw_事件中没有正确更新。修正是从这个答案,但修改也适用于几个数字

就如何获得因子的解释而言,MarkerUpdater实例包含一个dict,该dict为每个轴实例存储图形尺寸和添加add_ax时的轴限制。在draw_事件(例如,当调整图形大小或用户放大数据时触发)时,检索图形大小和轴限制的新当前值,并计算和存储缩放因子,以便放大和增加图形大小使标记变大。因为x和y维度可能以不同的速率变化,所以我使用min从两个计算因子中选择一个,并始终根据图形的原始大小进行缩放

如果希望使用不同的函数缩放alpha,可以轻松更改调整alpha值的线条。例如,如果你想要幂律而不是线性递减,你可以写path.set_alphaalpha*facA**n,其中n是幂

from matplotlib import pyplot as plt
import numpy as np

##plt.switch_backend('TkAgg')
class MarkerUpdater:
    def __init__(self):
        ##for storing information about Figures and Axes
        self.figs = {}

        ##for storing timers
        self.timer_dict = {}

    def add_ax(self, ax, features=[]):
        ax_dict = self.figs.setdefault(ax.figure,dict())
        ax_dict[ax] = {
            'xlim' : ax.get_xlim(),
            'ylim' : ax.get_ylim(),
            'figw' : ax.figure.get_figwidth(),
            'figh' : ax.figure.get_figheight(),
            'scale_s' : 1.0,
            'scale_a' : 1.0,
            'features' : [features] if isinstance(features,str) else features,
        }
        ax.figure.canvas.mpl_connect('draw_event', self.update_axes)

    def update_axes(self, event):

        for fig,axes in self.figs.items():
            if fig is event.canvas.figure:

                for ax, args in axes.items():
                    ##make sure the figure is re-drawn
                    update = True

                    fw = fig.get_figwidth()
                    fh = fig.get_figheight()
                    fac1 = min(fw/args['figw'], fh/args['figh'])


                    xl = ax.get_xlim()
                    yl = ax.get_ylim()
                    fac2 = min(
                        abs(args['xlim'][1]-args['xlim'][0])/abs(xl[1]-xl[0]),
                        abs(args['ylim'][1]-args['ylim'][0])/abs(yl[1]-yl[0])
                    )

                    ##factor for marker size
                    facS = (fac1*fac2)/args['scale_s']

                    ##factor for alpha -- limited to values smaller 1.0
                    facA = min(1.0,fac1*fac2)/args['scale_a']

                    ##updating the artists
                    if facS != 1.0:
                        for line in ax.lines:
                            if 'size' in args['features']:
                                line.set_markersize(line.get_markersize()*facS)

                            if 'alpha' in args['features']:
                                alpha = line.get_alpha()
                                if alpha is not None:
                                    line.set_alpha(alpha*facA)


                        for path in ax.collections:
                            if 'size' in args['features']:
                                path.set_sizes([s*facS**2 for s in path.get_sizes()])

                            if 'alpha' in args['features']:
                                alpha = path.get_alpha()
                                if alpha is not None:
                                    path.set_alpha(alpha*facA)

                        args['scale_s'] *= facS
                        args['scale_a'] *= facA

                self._redraw_later(fig)



    def _redraw_later(self, fig):
        timer = fig.canvas.new_timer(interval=10)
        timer.single_shot = True
        timer.add_callback(lambda : fig.canvas.draw_idle())
        timer.start()

        ##stopping previous timer
        if fig in self.timer_dict:
            self.timer_dict[fig].stop()

        ##storing a reference to prevent garbage collection
        self.timer_dict[fig] = timer

if __name__ == '__main__':
    my_updater = MarkerUpdater()

    ##setting up the figure
    fig, axes = plt.subplots(nrows = 2, ncols =2)#, figsize=(1,1))
    ax1,ax2,ax3,ax4 = axes.flatten()

    ## a line plot
    x1 = np.linspace(0,np.pi,30)
    y1 = np.sin(x1)
    ax1.plot(x1, y1, 'ro', markersize = 10, alpha = 0.8)
    ax3.plot(x1, y1, 'ro', markersize = 10, alpha = 1)

    ## a scatter plot
    x2 = np.random.normal(1,1,30)
    y2 = np.random.normal(1,1,30)
    ax2.scatter(x2,y2, c = 'b', s = 100, alpha = 0.6)

    ## scatter and line plot
    ax4.scatter(x2,y2, c = 'b', s = 100, alpha = 0.6)
    ax4.plot([0,0.5,1],[0,0.5,1],'ro', markersize = 10) ##note: no alpha value!

    ##setting up the updater
    my_updater.add_ax(ax1, ['size'])  ##line plot, only marker size
    my_updater.add_ax(ax2, ['size'])  ##scatter plot, only marker size
    my_updater.add_ax(ax3, ['alpha']) ##line plot, only alpha
    my_updater.add_ax(ax4, ['size', 'alpha']) ##scatter plot, marker size and alpha

    plt.show()

回答得真好!上一次尝试中出现了一个小错误,除了两次阻止ax2而不是ax,我现在已经修复了它。我认为连接到draw事件本身就足够了,如[this answer]中所示。噢,缺少链接,[this answer]应该链接到解决方案是类似的,但我还没有检查它需要在多大程度上适应这里使用的非相等方面。此外,alpha不受其他问题的约束,因此我不会关闭此对话框。@adr请查看我的最新编辑。我添加了一些代码的解释,并修复了没有正确更新的图形。回答很好!上一次尝试中出现了一个小错误,除了两次阻止ax2而不是ax,我现在已经修复了它。我认为连接到draw事件本身就足够了,如[this answer]中所示。噢,缺少链接,[this answer]应该链接到解决方案是类似的,但我还没有检查它需要在多大程度上适应这里使用的非相等方面。此外,alpha不受其他问题的约束,因此我不会关闭此对话框。@adr请查看我的最新编辑。我对代码做了一些解释,并对没有正确更新的图形进行了修复
以数据单位表示,而不是以点表示。如何做到这一点将显示在中。似乎您希望以数据单位而不是点来显示标记大小。如何做到这一点将显示在中。