如何修改已创建的matplotlib传奇?

时间:2023-01-20 21:21:19

I have access to the figure instance fig = pylab.gcf(). I know that in this figure there is a legend and I can access it via myLegend = fig.gca().legend_. Now I want to change the properties of the legend. Some of them I have access via setters like myLegend.set_frame_on(True).

我可以访问图实例fig = pylab.gcf()。我知道在这个图形中有一个传说,我可以通过myLegend = fig.gca()。现在我要改变图例的属性。其中一些我可以通过setter来访问,比如my传奇。set_frame_on(True)。

When the legend is created it accepts a number of keyword arguments:

当创建传奇时,它接受许多关键字参数:

class matplotlib.legend.Legend(parent, handles, labels, loc=None, numpoints=None, markerscale=None, scatterpoints=None, scatteryoffsets=None, prop=None, fontsize=None, borderpad=None, labelspacing=None, handlelength=None, handleheight=None, handletextpad=None, borderaxespad=None, columnspacing=None, ncol=1, mode=None, fancybox=None, shadow=None, title=None, framealpha=None, bbox_to_anchor=None, bbox_transform=None, frameon=None, handler_map=None)

类matplotlib.legend。style = ' font - family:宋体;mso - ascii - font - family: tahoma; mso - hansi - font - family:

How can I modify all the keyword arguments in the legend after the legend is created?

如何在创建传奇之后修改传奇中的所有关键字参数?

One of the problematic ones is numpoints (number of markers in a legend, default is 2). Below is the example how I want to change it:

其中一个问题是numpoints(一个图例中的标记数,默认值是2)。

This shows how I want to program it

这显示了我想如何编程

import pylab
pylab.plot(0,0,'ro', label = 'one point')
pylab.legend(loc = "lower left")
# no modifications above this line
setattr(pylab.gcf().gca().legend_, 'numpoints',1)
pylab.show()

This shows how I want it to look like

这显示了我想要的样子

import pylab
pylab.plot(0,0,'ro', label = 'one point')
pylab.legend(numpoints = 1, loc = "lower left")
pylab.show()

I have cheked the source code, there is a numpoint variable that is changed, but the upper case is not updated to screen. What am I missing?

我已经修改了源代码,有一个numpoint变量被修改了,但是上面的大小写并没有更新到screen。我缺少什么?

4 个解决方案

#1


3  

I've written a function modify_legend which modifies a legend after it has been created. It basically reads all the parameters from the already created legend, updates it with the key-value parameters you provided and calls legend(...) with all possible parameters again.

我编写了一个函数modify_legend,它在创建传奇之后修改传奇。它基本上是从已经创建的传奇中读取所有的参数,用您提供的键值参数更新它,并再次使用所有可能的参数调用legend(…)。

Your problem would then be solved with:

你的问题将通过:

import pylab
pylab.plot(0,0,'ro', label = 'one point')
pylab.legend(loc = "lower left")

modify_legend(numpoints = 1)

pylab.show()

Here's the code for modify_legend:

以下是modify_legend代码:

def modify_legend(**kwargs):
    import matplotlib as mpl

    l = mpl.pyplot.gca().legend_

    defaults = dict(
        loc = l._loc,
        numpoints = l.numpoints,
        markerscale = l.markerscale,
        scatterpoints = l.scatterpoints,
        scatteryoffsets = l._scatteryoffsets,
        prop = l.prop,
        # fontsize = None,
        borderpad = l.borderpad,
        labelspacing = l.labelspacing,
        handlelength = l.handlelength,
        handleheight = l.handleheight,
        handletextpad = l.handletextpad,
        borderaxespad = l.borderaxespad,
        columnspacing = l.columnspacing,
        ncol = l._ncol,
        mode = l._mode,
        fancybox = type(l.legendPatch.get_boxstyle())==mpl.patches.BoxStyle.Round,
        shadow = l.shadow,
        title = l.get_title().get_text() if l._legend_title_box.get_visible() else None,
        framealpha = l.get_frame().get_alpha(),
        bbox_to_anchor = l.get_bbox_to_anchor()._bbox,
        bbox_transform = l.get_bbox_to_anchor()._transform,
        frameon = l._drawFrame,
        handler_map = l._custom_handler_map,
    )

    if "fontsize" in kwargs and "prop" not in kwargs:
        defaults["prop"].set_size(kwargs["fontsize"])

    mpl.pyplot.legend(**dict(defaults.items() + kwargs.items()))

Notes on the code:

笔记的代码:

  • Some parameters could easily be read from the Legend object, others (like title, fancybox) required some 'artistics'. You could check matplotlib.legend.Legend.__init__ to see how and why it's done.
  • 一些参数可以很容易地从Legend对象中读取,其他参数(如title、fancybox)则需要一些“技术人员”。你可以检查matplotlib.legend.Legend。我想看看这是怎么做的,为什么要这么做。
  • The extra condition on the fontsize parameter is used for overriding the font size when the legend was originally created with a prop, as prop usually overwrites fontsize.
  • fontsize参数上的额外条件用于覆盖字体大小,当图例最初是用一个prop创建时,因为prop通常会覆盖fontsize。
  • I did not test all the cases as I don't have much time (especially the bbox_to_anchor and bbox_transform-parameters), so feel free to try out and improve the code :)
  • 我没有测试所有的情况,因为我没有太多的时间(特别是bbox_to_anchor和bbox_transform-parameters),所以可以尝试并改进代码:

#2


2  

You can use the command pylab.legend again with the correct keywords/arguments. This will modify the existent legend instead of creating a new one. Bellow you find your example, slightly modified.

您可以使用pylab命令。再次使用正确的关键字/参数。这将修改现有的图例,而不是创建一个新的图例。您可以找到您的示例,稍作修改。

import pylab
pylab.plot(0,0,'ro', label = 'one point')
pylab.legend(loc = "lower left")
# Change the number of markers shown in the legend
pylab.legend(numpoints = 1, loc = "lower left")

pylab.show()

Hope it helps.

希望它可以帮助。

#3


1  

What you see in the legend actually is a Line2D. Altering numpoints after that line has been created won't update said line, so you will have to get a handle on the Line2D object and remove one of the points manually:

你在图例中看到的实际上是一个Line2D。在创建了这条线之后更改数字不会更新这条线,因此您必须获得Line2D对象的句柄,并手动删除其中的一个点:

import pylab
pylab.plot(0,0,'ro', label = 'one point')
legend = pylab.legend(loc = "lower left")
markers = legend.get_children()[0].get_children()[1].get_children()[0].get_children()[0].get_children()[0].get_children()[1]
markers.set_data(map(pylab.mean, markers.get_data()))
pylab.show()

The get_children() chain is required because matplotlib wraps the line in several layers of horizontal and vertical packs. The above snippet should suffice to give you the general idea, but in a real-world application, a preferable way to obtain the handle would be to follow the legend guide's hint on legend handlers and use a customized HandlerLine2D that stores the line in some fashion.

get_children()链是必需的,因为matplotlib将行封装在几个水平和垂直包层中。上面的代码片段应该足以让您大致了解这个概念,但是在实际应用程序中,获得句柄的更好方法是遵循传奇指南对传奇处理程序的提示,并使用定制的HandlerLine2D,以某种方式存储行。

#4


-1  

If this were me I would put it into another text file in order to do this, since it will be easier to change and keep track of, especially if you have a lot of code before and after this.

如果这是我,我会把它放到另一个文本文件中,这样做,因为它更容易更改和跟踪,特别是如果您在此之前和之后有很多代码。

To open a file for writing we set the second parameter to "w" instead of "r".(of fobj = open("ad_lesbiam.txt", "r")) To actually write the data into this file, we use the method write() of the file handle object.

要打开要写入的文件,我们将第二个参数设置为“w”而不是“r”。(fobj =(“ad_lesbiam开放。要实际地将数据写入这个文件,我们使用file handle对象的方法write()。

Let's start with a very simple and straightforward example:

让我们从一个非常简单明了的例子开始:

fh = open("example.txt", "w")
fh.write("To write or not to write\nthat is the question!\n")
fh.close()

Especially if you are writing to a file, you should never forget to close the file handle again. Otherwise you will risk to end up in a non consistent state of your data.

特别是如果您正在写文件,您应该永远不会忘记再次关闭文件句柄。否则,您将有可能以不一致的数据状态结束。

You will often find the with statement for reading and writing files. The advantage is that the file will be automatically closed after the indented block after the with has finished execution:

您经常会找到用于读写文件的with语句。这样做的好处是,在with完成执行后,在缩进块之后,文件会自动关闭:

with open("example.txt", "w") as fh:
    fh.write("To write or not to write\nthat is the question!\n")

Our first example can also be rewritten like this with the with statement:

我们的第一个例子也可以用with语句来重写:

with open("ad_lesbiam.txt") as fobj:
    for line in fobj:
        print(line.rstrip())

Example for simultaneously reading and writing:

同时读写的例子:

fobj_in = open("ad_lesbiam.txt")
fobj_out = open("ad_lesbiam2.txt","w")
i = 1
for line in fobj_in:
    print(line.rstrip())
    fobj_out.write(str(i) + ": " + line)
    i = i + 1
fobj_in.close()
fobj_out.close()

FYI. Every line of the input text file is prefixed by its line number

仅供参考。输入文本文件的每一行都由其行号前缀。

#1


3  

I've written a function modify_legend which modifies a legend after it has been created. It basically reads all the parameters from the already created legend, updates it with the key-value parameters you provided and calls legend(...) with all possible parameters again.

我编写了一个函数modify_legend,它在创建传奇之后修改传奇。它基本上是从已经创建的传奇中读取所有的参数,用您提供的键值参数更新它,并再次使用所有可能的参数调用legend(…)。

Your problem would then be solved with:

你的问题将通过:

import pylab
pylab.plot(0,0,'ro', label = 'one point')
pylab.legend(loc = "lower left")

modify_legend(numpoints = 1)

pylab.show()

Here's the code for modify_legend:

以下是modify_legend代码:

def modify_legend(**kwargs):
    import matplotlib as mpl

    l = mpl.pyplot.gca().legend_

    defaults = dict(
        loc = l._loc,
        numpoints = l.numpoints,
        markerscale = l.markerscale,
        scatterpoints = l.scatterpoints,
        scatteryoffsets = l._scatteryoffsets,
        prop = l.prop,
        # fontsize = None,
        borderpad = l.borderpad,
        labelspacing = l.labelspacing,
        handlelength = l.handlelength,
        handleheight = l.handleheight,
        handletextpad = l.handletextpad,
        borderaxespad = l.borderaxespad,
        columnspacing = l.columnspacing,
        ncol = l._ncol,
        mode = l._mode,
        fancybox = type(l.legendPatch.get_boxstyle())==mpl.patches.BoxStyle.Round,
        shadow = l.shadow,
        title = l.get_title().get_text() if l._legend_title_box.get_visible() else None,
        framealpha = l.get_frame().get_alpha(),
        bbox_to_anchor = l.get_bbox_to_anchor()._bbox,
        bbox_transform = l.get_bbox_to_anchor()._transform,
        frameon = l._drawFrame,
        handler_map = l._custom_handler_map,
    )

    if "fontsize" in kwargs and "prop" not in kwargs:
        defaults["prop"].set_size(kwargs["fontsize"])

    mpl.pyplot.legend(**dict(defaults.items() + kwargs.items()))

Notes on the code:

笔记的代码:

  • Some parameters could easily be read from the Legend object, others (like title, fancybox) required some 'artistics'. You could check matplotlib.legend.Legend.__init__ to see how and why it's done.
  • 一些参数可以很容易地从Legend对象中读取,其他参数(如title、fancybox)则需要一些“技术人员”。你可以检查matplotlib.legend.Legend。我想看看这是怎么做的,为什么要这么做。
  • The extra condition on the fontsize parameter is used for overriding the font size when the legend was originally created with a prop, as prop usually overwrites fontsize.
  • fontsize参数上的额外条件用于覆盖字体大小,当图例最初是用一个prop创建时,因为prop通常会覆盖fontsize。
  • I did not test all the cases as I don't have much time (especially the bbox_to_anchor and bbox_transform-parameters), so feel free to try out and improve the code :)
  • 我没有测试所有的情况,因为我没有太多的时间(特别是bbox_to_anchor和bbox_transform-parameters),所以可以尝试并改进代码:

#2


2  

You can use the command pylab.legend again with the correct keywords/arguments. This will modify the existent legend instead of creating a new one. Bellow you find your example, slightly modified.

您可以使用pylab命令。再次使用正确的关键字/参数。这将修改现有的图例,而不是创建一个新的图例。您可以找到您的示例,稍作修改。

import pylab
pylab.plot(0,0,'ro', label = 'one point')
pylab.legend(loc = "lower left")
# Change the number of markers shown in the legend
pylab.legend(numpoints = 1, loc = "lower left")

pylab.show()

Hope it helps.

希望它可以帮助。

#3


1  

What you see in the legend actually is a Line2D. Altering numpoints after that line has been created won't update said line, so you will have to get a handle on the Line2D object and remove one of the points manually:

你在图例中看到的实际上是一个Line2D。在创建了这条线之后更改数字不会更新这条线,因此您必须获得Line2D对象的句柄,并手动删除其中的一个点:

import pylab
pylab.plot(0,0,'ro', label = 'one point')
legend = pylab.legend(loc = "lower left")
markers = legend.get_children()[0].get_children()[1].get_children()[0].get_children()[0].get_children()[0].get_children()[1]
markers.set_data(map(pylab.mean, markers.get_data()))
pylab.show()

The get_children() chain is required because matplotlib wraps the line in several layers of horizontal and vertical packs. The above snippet should suffice to give you the general idea, but in a real-world application, a preferable way to obtain the handle would be to follow the legend guide's hint on legend handlers and use a customized HandlerLine2D that stores the line in some fashion.

get_children()链是必需的,因为matplotlib将行封装在几个水平和垂直包层中。上面的代码片段应该足以让您大致了解这个概念,但是在实际应用程序中,获得句柄的更好方法是遵循传奇指南对传奇处理程序的提示,并使用定制的HandlerLine2D,以某种方式存储行。

#4


-1  

If this were me I would put it into another text file in order to do this, since it will be easier to change and keep track of, especially if you have a lot of code before and after this.

如果这是我,我会把它放到另一个文本文件中,这样做,因为它更容易更改和跟踪,特别是如果您在此之前和之后有很多代码。

To open a file for writing we set the second parameter to "w" instead of "r".(of fobj = open("ad_lesbiam.txt", "r")) To actually write the data into this file, we use the method write() of the file handle object.

要打开要写入的文件,我们将第二个参数设置为“w”而不是“r”。(fobj =(“ad_lesbiam开放。要实际地将数据写入这个文件,我们使用file handle对象的方法write()。

Let's start with a very simple and straightforward example:

让我们从一个非常简单明了的例子开始:

fh = open("example.txt", "w")
fh.write("To write or not to write\nthat is the question!\n")
fh.close()

Especially if you are writing to a file, you should never forget to close the file handle again. Otherwise you will risk to end up in a non consistent state of your data.

特别是如果您正在写文件,您应该永远不会忘记再次关闭文件句柄。否则,您将有可能以不一致的数据状态结束。

You will often find the with statement for reading and writing files. The advantage is that the file will be automatically closed after the indented block after the with has finished execution:

您经常会找到用于读写文件的with语句。这样做的好处是,在with完成执行后,在缩进块之后,文件会自动关闭:

with open("example.txt", "w") as fh:
    fh.write("To write or not to write\nthat is the question!\n")

Our first example can also be rewritten like this with the with statement:

我们的第一个例子也可以用with语句来重写:

with open("ad_lesbiam.txt") as fobj:
    for line in fobj:
        print(line.rstrip())

Example for simultaneously reading and writing:

同时读写的例子:

fobj_in = open("ad_lesbiam.txt")
fobj_out = open("ad_lesbiam2.txt","w")
i = 1
for line in fobj_in:
    print(line.rstrip())
    fobj_out.write(str(i) + ": " + line)
    i = i + 1
fobj_in.close()
fobj_out.close()

FYI. Every line of the input text file is prefixed by its line number

仅供参考。输入文本文件的每一行都由其行号前缀。