Pandas: API:为 Pandas 绘图后端定义 API

创建于 2019-06-09  ·  44评论  ·  资料来源: pandas-dev/pandas

在 #26414 中,我们将 Pandas 绘图模块拆分为一个通用绘图框架,能够调用不同的后端和当前的 matplotlib 后端。 这个想法是其他后端可以以更简单的方式实现,并由 Pandas 用户与通用 API 一起使用。

当前 matplotlib 后端定义的 API 包括下面列出的对象,但这个 API 可能可以简化。 以下是问题/建议列表:

保留在 API 中的无争议方法(它们提供Series.plot(kind='line') ... 功能):

  • 线图
  • 条形图
  • 柱状图
  • 历史图
  • 箱形图
  • KdePlot
  • 面积图
  • 饼图
  • 散点图
  • 十六进制图

大熊猫提供的绘图功能(例如pandas.plotting.andrews_curves(df)

  • 安德鲁斯_曲线
  • 自相关图
  • bootstrap_plot
  • 滞后图
  • 平行坐标
  • 拉维兹
  • scatter_matrix
  • 桌子

这些应该是 API 的一部分,其他后端也应该实现它们吗? 转换为.plot格式(例如DataFrame.plot(kind='autocorrelation') ...)有意义吗? 远离 API 或转移到第三方模块是否有意义?

可以删除的冗余方法:

  • hist_series
  • hist_frame
  • 箱形图
  • boxplot_frame
  • boxplot_frame_groupby

boxplot的情况下,我们目前有几种生成绘图的方法(主要调用相同的代码):

  1. DataFrame.plot.boxplot()
  2. DataFrame.plot(kind='box')
  3. DataFrame.boxplot()
  4. pandas.plotting.boxplot(df)

就个人而言,我会弃用数字 4,对于数字 3,弃用或至少不需要在后端使用单独的boxplot_frame方法,但尝试重用BoxPlot (对于数字 3 评论,相同适用于hist )。

对于boxplot_frame_groupby ,没有详细检查,但不确定BoxPlot是否可以重复使用?

注册转换器的函数:

  • 登记
  • 注销

这些对其他后端有意义吗?

在 pandas 0.23 中已弃用,待删除:

  • tsplot

要查看这些函数在实践中的作用, @liirusuk 的这个笔记本可能很有用: https :

抄送:@pandas-dev/pandas-core @ tacaswell@jakevdp@philippjfr 、@PatrikHlobil

API Design Clean Needs Discussion Visualization

最有用的评论

这是一个基于入口点的实现

diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py
index 0610780ed..c8ac12901 100644
--- a/pandas/plotting/_core.py
+++ b/pandas/plotting/_core.py
@@ -1532,8 +1532,10 @@ class PlotAccessor(PandasObject):

         return self(kind="hexbin", x=x, y=y, C=C, **kwargs)

+_backends = {}

-def _get_plot_backend(backend=None):
+
+def _get_plot_backend(backend="matplotlib"):
     """
     Return the plotting backend to use (e.g. `pandas.plotting._matplotlib`).

@@ -1546,7 +1548,14 @@ def _get_plot_backend(backend=None):
     The backend is imported lazily, as matplotlib is a soft dependency, and
     pandas can be used without it being installed.
     """
-    backend_str = backend or pandas.get_option("plotting.backend")
-    if backend_str == "matplotlib":
-        backend_str = "pandas.plotting._matplotlib"
-    return importlib.import_module(backend_str)
+    import pkg_resources  # slow import. Delay
+    if backend in _backends:
+        return _backends[backend]
+
+    for entry_point in pkg_resources.iter_entry_points("pandas_plotting_backends"):
+        _backends[entry_point.name] = entry_point.load()
+
+    try:
+        return _backends[backend]
+    except KeyError:
+        raise ValueError("No backend {}".format(backend))
diff --git a/setup.py b/setup.py
index 53e12da53..d2c6b18b8 100755
--- a/setup.py
+++ b/setup.py
@@ -830,5 +830,10 @@ setup(
             "hypothesis>=3.58",
         ]
     },
+    entry_points={
+        "pandas_plotting_backends": [
+            "matplotlib = pandas:plotting._matplotlib",
+        ],
+    },
     **setuptools_kwargs
 )

我觉得还不错。 第 3 方软件包将修改它们的 setup.py(或 pyproject.toml)以包含类似的内容

entry_points={
    "pandas_plotting_backends": ["altair = pdvega._pandas_plotting_backend"]
}

我喜欢它打破命名和实现之间的紧密耦合。

所有44条评论

我认为将自相关之类的东西排除在可交换后端 API 之外。

我认为我们保留了 df.boxplot 和 hist 之类的东西,因为它们的行为与 .plot API 略有不同。 我不建议将它们作为后端 API 的一部分。

这是我几个月前提出的后端 API 的开始: https :

我认为值得一提的是,至少hvplot (没有检查其余部分)确实已经提供了诸如andrews_curvesscatter_matrixlag_plot 。 ..

可能是如果我们不想强制所有后端实现这些,我们可以检查所选后端是否实现它们,并默认为 matplotlib 图?

我假设boxplothist行为完全相同,但只有Series.plot.hist()快捷方式Series.hist() Series.plot.hist() 。 “快捷方式”显示了绘图网格,但除此之外我没有看到任何区别。

IMO,此选项的主要值是.plot命名空间。

如果用户想要 hvplot 的安德鲁曲线图,他们应该导入函数
从 hvplot 并在那里传递数据框。

在 2019 年 6 月 9 日星期日上午 7 点 17 分,Marc Garcia [email protected]写道:

我认为值得一提的是,至少 hvplot(没有检查
休息)确实已经提供了像andrews_curves这样的功能,
scatter_matrix、lag_plot、...

可能是如果我们不想强制所有后端都实现这些,我们可以
检查所选后端是否实现它们,并默认为
matplotlib 绘图?

我假设 boxplot 和 hist 的行为完全相同,但只是有
Series.plot.hist() 的快捷方式 Series.hist()。 “快捷方式”显示
绘图网格,但除此之外我没有看到任何区别。


您收到此消息是因为您所在的团队已被提及。
直接回复本邮件,在GitHub上查看
https://github.com/pandas-dev/pandas/issues/26747?email_source=notifications&email_token=AAKAOIRLJHBMXMXKK2IG2NDPZTYFPA5CNFSM4HWIMEK2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63KDMX700000000000000000000000
或静音线程
https://github.com/notifications/unsubscribe-auth/AAKAOISDHL6H7PVOOJAQXELPZTYFPANCNFSM4HWIMEKQ
.

我认为这是有道理的,但如果我们这样做,我认为我们应该将它们移动到pandas.plotting.matplotlib.andrews_curves ,而不是pandas.plotting.andrews_curves

@TomAugspurger我需要更详细地检查,但我认为你在https://github.com/TomAugspurger/pandas/commit/b07aba28a37b0291fd96a1f571848a7be2b6de8d 中实现的 API 更有意义。 完成#26753 后,我将继续努力。 我还将尝试将andrews_curvesscatter_matrix ... 移动到.plot()语法是否可行,我认为这将使每个人(我们、第三方库和用户)。

这里关于传递给绘图函数的额外 kwargs 的意图是什么? 其他后端是否应该尝试复制所有 matplotlib 样式的绘图自定义的功能,还是应该允许传递与特定后端使用的关键字相对应的关键字?

第一个选项在理论上会很好,但需要每个非 matplotlib 绘图后端基本上实现自己的 matplotlib 转换层,其中包含一长串的不兼容问题,这些问题基本上永远不会完成(从尝试创建 mpld3 的人的经验说起)几年前)。

从可互换性的角度来看,第二个选项不太好,但可以允许添加其他后端并具有更合理的期望。

我认为这取决于后端如何处理它们。 实现 100%
跨后端的兼容性并不真正可行,
因为返回类型不再是 matplotlib Axes。 而如果
我们在返回类型上不兼容,我不认为后端
应该向后弯曲以尝试处理每个可能的关键字参数。

所以我认为熊猫应该记录**kwargs将被传递给
底层绘图引擎,他们可以随心所欲
他们。

2019 年 6 月 10 日星期一上午 10:42 Jake Vanderplas [email protected]
写道:

关于传递给绘图的额外 kwargs 的意图是什么
职能? 如果其他后端尝试复制
所有 matplotlib 样式的绘图自定义的功能,或者它们应该
允许传递与特定对象使用的关键字相对应的关键字
后端?

第一个选项理论上很好,但需要每个
非 matplotlib 绘图后端基本上实现了自己的 matplotlib
具有长尾不兼容性的转换层
基本上永远不会是完整的(从经验来说
几年前曾尝试创建 mpld3)。

从的角度来看,第二种选择并不好
可互换性,但允许其他后端添加更多
合理的预期。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/pandas-dev/pandas/issues/26747?email_source=notifications&email_token=AAKAOIS3IBV4XSSY7BPSCF3PZZY5LA5CNFSM4HWIMEK2YY3PNVWWK3TUL52HS4DFVREXG43MVVMVBWZKLOM504MVVMVBWZKLOM504MVWWWWZKLOM504MVWWWWZHW500XHW500X52000000001
或静音线程
https://github.com/notifications/unsubscribe-auth/AAKAOIQ3GYOGAPUZ4LSNK2DPZZY5LANCNFSM4HWIMEKQ
.

如果这是一个愚蠢的问题,我很抱歉,但是如果您定义一个绘图“API”,它基本上是一组罐头绘图,是不是每个后端都会产生或多或少相同的输出? 这意味着要启用什么新功能? 像熊猫到vega出口商之类的东西?

我认为说每个后端产生或多或少相同的输出是不正确的。

例如,matplotlib 非常擅长静态图表,但不擅长制作便携式交互式图表。

另一方面,散景、altair 等。 非常适合交互式图表,但不如用于静态图表的 matplotlib 成熟。

能够使用相同的 API 生成两者将是一个巨大的胜利。

第一个选项在理论上会很好,但需要每个非 matplotlib 绘图后端基本上实现自己的 matplotlib 转换层,其中包含一长串的不兼容问题,这些问题基本上永远不会完成(从尝试创建 mpld3 的人的经验说起)几年前)。

并且将 Matplotlib 固定得比我们已经知道的 API 还要多。 我认为 Pandas 声明它想要公开的样式旋钮是有道理的,并期望后端实现能够弄清楚这意味着什么。 这可能意味着_不_盲目地传递**kwargs ,而是确保返回的对象是给定后端的“正确事物”,以便能够进行事后样式定制。

例如,matplotlib 非常擅长静态图表,但不擅长制作便携式交互式图表。

谢谢@jakevdp ,是的,支持交互式图表是一个很好的目标。

在事情走得太远之前,这里有一个替代解决方案。

与其宣布 Pandas 绘图 API 现在是一个规范,并要求可视化包专门实现它,为什么不生成绘图的中间表示(如 vega JSON 文件),并鼓励后端将其作为他们的输入。

优点包括:

  1. 不受具体化的 Pandas API 的表达能力的束缚,该 API 不是作为规范设计的。
  2. 通过绘制支持 Pandas 的包完成的工作可用于其他生成 IR 的 pydata 包。
  3. 在 pydata 空间中推广一种用于交换可视化的通用语言
  4. 这使得新工具更强大,因为适用范围更广
  5. 这使得编写它们的努力更加合理。 基本上,改进的激励措施。

Vega/Vega-lite作为一种现代的、成熟的、开放的、基于 JSON 的可视化规范语言,在设计和实现中投入了数年的时间,并且围绕它构建的现有工具似乎是专门为此目的而创建的. (只是请不要)。

你知道, frontend->IR->backend ,就像编译器的设计。

至少三个包已经实现了 API。 pandas 需要做的就是提供一个选项来更改后端并记录其使用,这对我们来说似乎是一个不错的选择。

在2019年6月15日,在16:28,pilkibun [email protected]写道:

例如,matplotlib 非常擅长静态图表,但不擅长制作便携式交互式图表。

谢谢@jakevdp ,是的,支持交互式图表是一个很好的目标。

在事情走得太远之前,这里有一个替代解决方案。

与其宣布 Pandas 绘图 API 现在是一个规范,并要求可视化包专门实现它,为什么不生成绘图的中间表示(如 vega JSON 文件),并鼓励后端将其作为他们的输入。

优点包括:

不受具体化的 Pandas API 的表达能力的束缚,该 API 不是作为规范设计的。
通过绘制支持 Pandas 的包完成的工作可用于其他生成 IR 的 pydata 包。
在 pydata 空间中推广一种用于交换可视化的通用语言
这使得新工具更强大,因为适用范围更广
这使得编写它们的努力更加合理。 基本上,改进的激励措施。
Vega/Vega-lite,作为一种现代的、成熟的、开放的、基于 JSON 的可视化规范语言,在其设计和实现中投入了数年的时间,并且围绕它构建的现有工具似乎是专门为此目的而创建的. (只是请不要)。

要知道,frontend->IR->backend,就像编译器的设计。


你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看,或将线程静音。

我们现在合并了#26753,并且可以从pandas 更改绘图后端。 当我们拆分 matplotlib 代码时,我们将SeriesPlotMethodsFramePlotMethods留在了熊猫(不是 matplotlib)一侧。 这主要是为了将文档字符串留在熊猫这边。

但我看到后端所做的是重新实现这些类。 所以,目前我们希望后端每个图有一个类(例如LinePlotBarPlot ),但是他们实现了一个每个方法都有一个图的类(例如hvPlot, or the same names as pandas for pdvega `)。

我认为有意义的,至少作为第一个版本,是我们按照hvplotpdvega实现的 API。 我只是在熊猫中创建一个抽象类,后端继承自。

如果这对每个人都有意义,我将首先创建抽象类并调整我们在 Pandas 中的 matplotlib 后端,一旦完成,我们调整hvplotpdvega (更改应该很小)。

想法?

我认为有意义的,至少作为第一个版本,是我们像 hvplot 和 pdvega 那样实现 API。 我只是在熊猫中创建一个抽象类,后端继承自。

我认为总的来说,这种方法会更干净。 我无法与其他绘图后端交谈,但至少在 hvPlot 中,不同的绘图方法共享相当多的代码,例如scatterlinearea基本上是类似的,并且我不想依赖子类在它们之间共享代码。 此外,我认为不同的后端应该可以选择添加额外的绘图类型,并将它们作为额外的公共方法公开似乎是最简单、最自然的方法。

只是为了确保我理解,当你说I'd prefer not to rely on subclassing to share code between them你的意思是像class LinePlot(MPLPlot) ,对吧? 不是说您认为从抽象基类继承是一个坏主意吗?

我想我对让后端定义不在 Pandas 中的绘图类型持 +1 意见。 但我现在可能不会实施它。 我们计划在一周左右发布熊猫。 而且我认为如果用户提供kind='foo'并且后端提供方法foo (例如,参数验证,否则会导致一些kind将在文档中,有些则不会)。

只是为了确保我理解,当您说我不想依赖子类化在它们之间共享代码时,您的意思是像 LinePlot(MPLPlot) 类中那样,对吗? 不是说您认为从抽象基类继承是一个坏主意吗?

恩,那就对了。 更具体地说,我宁愿不必做这种事情:

class MPL1dPlot(MPLPlot):

    def _some_shared_method(self, ...):
        ...

class LinePlot(MPL1dPlot):
    ...

class AreaPlot(MPL1dPlot):
    ...

抱歉,如果不清楚。

非常赞成更简单的 API,它作为单个函数而不是现在在https://github.com/pandas-dev/pandas/pull/27009 中提出的类公开公开

关于后端选项现在如何工作的一般问题/评论。 假设我是pdvega开发人员,并让这个后端可用。 这意味着如果用户执行pd.options.plotting.backend = 'pdvega' ,那么pdvega库需要具有顶级plot函数吗?
1) 作为库作者,这不一定是您想要公开的功能(也就是说,对于从库的角度来看的顶级plot方法,不一定是您希望用户使用的 API直接使用) 和 2) 对于这种情况,您实际上可能希望能够执行pd.options.plotting.backend = 'altair' ? (以防 Altair 开发人员对此感到满意)
所以基本上我的问题是:后端名称和导入的内容是否需要精确的 1:1 映射? (现在需要它,因为它只是导入提供的后端字符串)。

编辑:我看到 PR #26753 中实际上讨论了类似的内容

如果我们决定 pandas 不知道/限制可以使用哪些后端(我强烈支持这样做),我们需要决定如何/在后端调用什么。

它在我正在处理的 PR 中实现和提出的是选项plotting.backend是一个模块(可以是pdvegaaltairaltair.pandas ,或其他),并且该模块必须具有公共plot函数,我们将调用该函数。

我们可以考虑其他选项,比如如果选项是pdvega ,我们导入pdvega.pandas ,或者我们可以命名函数plot_pandas或其他什么。 我认为建议的方式是最简单的,但如果有其他更有意义的建议,我很乐意更改它。

另一个讨论是我们是否要强制用户手动导入后端:

import pandas
import hvplot

pandas.Series([1, 2, 3]).plot()

如果我们这样做,模块可以注册自己,它们也可以注册别名(因此set_option可以理解模块名称以外的其他名称)。 他们还可以实现自定义功能或机制(例如上下文管理器)以使用某些后端进行绘图,...我个人认为,我们保持的东西越简单越好。

虽然用pandas.set_option('plotting.backend', 'bokeh')在散景中绘图可能会很好,但我认为这意味着我个人不喜欢的两件事:

  • pandas.set_option('plotting.backend', 'bokeh')仅在调用了import pandas_bokeh时才有效,并且会使用户感到困惑。
  • 这也意味着在bokeh只有一个模块可以绘制。 这不一定是真的,并且会给用户错误的印象,即您直接使用散景绘制,而不是使用 Pandas 绘制散景后端。

@datapythonista感谢您的详细回答。 我现在可以将它保留为初始版本(以后总是可以添加别名的可能性)。

如果用户想要 hvplot 的安德鲁曲线图,他们应该从 hvplot 导入函数并将数据框传递到那里。

+1,我也不会通过后端公开所有额外的绘图功能。

但是关于将它们移动到pandas.plotting.matplotlib ,这对我来说似乎是一个不必要的向后不兼容的中断(假设您的意思不仅是移动实现)。

pandas.set_option('plotting.backend', 'bokeh') 仅在调用了 import pandas_bokeh 时才有效,并且会让用户感到困惑。

如果我们使用入口点来注册扩展,则不必如此:将包安装在系统上将注册入口点并使其对 Pandas 可见。 例如,这是 Altair 用来检测用户可能已安装的各种渲染器的工具。

此外,对于它的价值,一旦进入我想我可能会弃用 pdvega 并将相关代码移到一个名为pandas_altair或类似的新包中。

@datapythonista我认为我们应该在 0.25.0 之前决定绘图后端 API 的范围(但不适用于 RC)。

您赞成保留 misc 绘图函数(以及 hist / boxplot)?

@datapythonista在我们合并 PR 时关闭它?

@jreback在我们就 API 达成一致之前,我会一直保持开放, @TomAugspurger@jorisvandenbossche除了访问器图之外不想将任何内容委托给后端。

我会为绘制熊猫做什么 - 后端是下一个。

对于发布:

  • 保持原样, hvplot 实现了所有的图,来自访问器的图和不是的图。 我认为委托一切使事情变得简单。
  • 不确定我是否会从上面排除 register_converters。 至少我们应该将名称从register_matplotlib_converters更改为我们委托他们

对于下一个版本:

  • 我会弃用所有重复的pandas.plotting.boxplotSeries.hist ,...
  • 我会移动所有要从访问器(andrew_curves、radviz、parallel_curves 等)调用的图。

对于后端 API 的初始版本,我宁愿在我们公开的内容上更加保守,而不是包含所有内容。 稍后添加东西比删除要容易得多。

我个人也不会将所有这些杂项图移动到访问器(可能有一些例外,例如散点矩阵),IMO 的 andrew_curves 和 radviz 等不“值得”使用一种方法。

也就是说:我们是否希望允许后端实现额外的“种类”? 因此,作为熊猫,我们不必确切地决定哪些访问器方法可用。 如果用户传递了某个kind或尝试访问一个属性,我们仍然可以使用自定义__getattribute__将它传递给后端plot __getattribute__

只是为了解释一下为什么事情会变成现在这样。 这是相关的,因为我不太确定如何实施您提出的更改,或者不公开一般情况。 这里不是说不能以不同的方式完成,只是为了丰富讨论。

第一个决定是将使用 matplotlib 的所有代码移动到一个单独的模块 ( pandas.plotting._matplotlib )。 通过这样做,该模块以某种方式成为了 matplotlib 后端。

pandas.plotting中公开的所有内容都在那里保持公开。 为了让事情尽可能简单,这些函数中的每一个,一旦被调用,它就会加载后端(调用_get_plot_backend )并在那里调用函数。

用户的公共API没有任何变化,用户仍然可以使用相同的方法和功能。 我们不会暴露任何新的东西。

我的理解是,如果我们决定不将像andrew_curves这样的现有绘图委托给后端,这意味着不是让用户选择后端,我们仍将选择 matplotlib 后端。 鉴于至少hvplot已经在实施andrew_curves ,我个人不明白这一点。 如果用户想要 matplotlib 中的andrew_curves绘图,就像不更改后端一样简单(如果更改了,则再次设置)。 因此,通过更改,我们所做的只是通过为 Pandas 增加额外的复杂性,让用户的生活变得更加艰难。

如果我们想与后端开发人员友好相处,而不是强迫他们实现可能不是那么主流的图(我想这是原因之一?),也许我们可以将所选后端中缺少的任何内容默认为 matplotlib 后端?

关于将任何未知类型的情节委派给后端,我现在做的 -1。 当然,它最终会有意义。 但是我认为在 Pandas 中记录了几种情节类型,并且有我们没有记录的额外情节,感觉有点麻烦。 我觉得可以等下个版本,等我们反馈了不同的后端如何为用户工作之后,我们有更多的时间来详细讨论和分析。

如果用户想要 matplotlib 中的 andrew_curves 图,就像不更改后端一样简单(如果更改了,则再次设置)。 因此,通过更改,我们所做的只是通过为 Pandas 增加额外的复杂性,让用户的生活变得更加艰难。

我认为我们不会让用户的生活变得更艰难。 如果他们想要一个 hvplot 的版本,而不是从 pandas.plotting 导入它,他们可以简单地从那里导入它。 这对于 DataFrame.plot 方法来说是不可能的,因为它是在对象上定义的。 对我来说,这是绘图后端的主要原因。

如果我们想与后端开发人员友好相处,而不是强迫他们实现可能不那么主流的情节

对我来说,这不是为了好看或需要实现所有东西(如果后端不支持所有绘图类型,IMO,那完全没问题),而是绘图后端 API 的不必要扩展,这也将我们与它联系起来.
如果我们从头开始重新启动 Pandas,我认为不会包括那些杂项绘图类型。 但是通过绘图后端 API,我们在某种程度上开始了一些新的事情。

对此还有其他意见吗?

同意@jorisvandenbossche。


为了确保这不会丢失,我认为@jakevdp建议使用 setuptool 的入口点来解决导入订单注册问题值得考虑: https :

@jorisvandenbossche您将如何更改代码中的内容? 不是获取在这些方法的设置中定义的后端,而是获取 matplotlib 后端? 我认为这在概念上是错误的,但如果达成一致,我可以接受。 任何恢复 matplotlib 代码与其余代码解耦的东西我都是 -1。

既然你从头开始提到在熊猫中我们不会包括这些情节,我们应该弃用它们吗? 我对将所有不是SeriesDataFrame方法的图移动到第三方包表示支持。 或者,如果有任何重要到需要保留,将其移动到.plot()作为其他调用。

我会弃用熊猫中的非标准图
并移动到外部包

Joris 离线了一段时间。

我认为,当我们过去讨论过这个问题时,他和我在论文上的立场是让它们保持原样,直到它们成为维护负担。

就这样我们在同一页面上,这是我们所拥有的摘要以及我对讨论状态的理解:

用作SeriesDataFrame (我们很高兴将它们保持原样,委托给选定的后端):

  • 绘图存取器
  • boxplot_frame
  • boxplot_frame_groupby
  • hist_frame
  • hist_series

其他图(正在讨论是否应该弃用、委托给 matplotlib 后端或委托给选定的后端):

  • 箱形图
  • scatter_matrix
  • 拉维兹
  • 安德鲁斯_曲线
  • bootstrap_plot
  • 平行坐标
  • 滞后图
  • 自相关图
  • 桌子

pandas.plotting其他公共内容(也在讨论中):

  • 绘图参数
  • register_matplotlib_converters
  • deregister_matplotlib_converters

对于Other plots部分,我个人认为在这一点上它们是维护负担,并且我对将它们从 Pandas 中移出 +1,并在 0.25 中弃用它们。

对于转换器和其他东西,我们现在拥有的肯定是不正确的,因为register_matplotlib_converters委托给选定的情节,这不能是 matplotlib。 我想我们可以考虑的选项是:

  • 将它们重命名为register_converters / deregister_converters ,弃用当前的,并继续委托给后端
  • 将它们从pandas.plottingpandas.plotting.matplotlib (这意味着将 matplotlib 后端公开,所以我不会)
  • 让它们保持原样,并委托给 matplotlib 后端而不是选定的后端(我认为这更像是一个黑客而不是一个好的设计决策,我更愿意让pandas.plotting知道存在哪些后端)

对于其他图部分,我个人认为此时它们是维护负担,我对将它们从 Pandas 中移出 +1,并在 0.25 中弃用它们。

您如何发现“其他地块”成为维护负担? 查看“misc”图的历史: https :

将它们重命名为 register_converters/deregister_converters,弃用当前的,并继续委托给后端

我认为这没有意义。 我们为 matplotlib 编写了特定于 matplotlib 的转换器。 其他后端不会有它们。 它可能不应该是后端 API 的一部分。

我并不是说这些图是一种负担,因为我们在过去几个月中进行了大量维护,而是因为他们认为现在为用户提供一致且直观的 API 以及良好的模块化为我们设计代码。

关于转换器,我不知道后端作者是否可能希望在某些情况下实现与 matplotlib 等效的转换器。 但是如果他们不这样做似乎没有问题,并且这些功能对某些或所有其他后端没有任何作用。 我也同意选项 2,但我觉得它不那么整洁。

但是因为他们认为现在的问题是为用户提供一致且直观的 API,以及为我们提供良好的模块化代码设计。

不过,它们与 DataFrame.plot 已经有些不一致了。 “misc”这个名字暗示:) 有一个可交换的后端会使情况变得更糟吗? 在多大程度上值得用户代码流失? 我不这么认为。

我不知道在某些情况下后端作者是否可能想要实现与 matplotlib 等效的那些。

我不这么认为。 这些转换器的重点是教 matplotlib 关于 Pandas 对象。 实现后端的库不会有这个问题,因为它们已经依赖于 Pandas。

我个人主要从管理复杂性的角度来考虑它。 拥有通过单个 API 委托给后端的标准绘图 API 很容易理解和维护。 用户和维护者只需要知道有一个带有kind参数的plot函数,并且这将在选定的后端执行。

在后端有一组异构图,除了不遵循相同的 API 外,还使用后端,但不是为其他图选择的后端,而是 Matplotlib 的后端,恕我直言,为每个人增加了太多的复杂性。

移动它们的成本对我来说似乎很小,我的猜测是我们的用户中没有很大一部分甚至知道这些地块。 对于那些这样做的人,他们只需要安装一个额外的 conda 包并使用import pandas_plotting; pandas_plotting.andrews_curves(df)而不是pandas.plotting.andrews_curves(df)

对我来说,以很小的代价赢得很多东西,但这当然只是一种意见。

我们能否证明可交换后端仅用于 Series/DataFrame.plot? 这似乎是一个非常简单的规则。

感觉就像一个 hack,给我增加了不必要的复杂性; 我认为在文档中解释它不会让它不那么违反直觉。

但无论如何,也没什么大不了的。 如果这是首选选项,这就是我实现它的方式,至少代码复杂性的增加是最小的:#27432

现在更仔细地观察:如果我理解正确,绘图后端的设置方式是使用:

pd.set_option('plotting.backend', 'name_of_module')

那么,我的理解是,如果我想做以下工作:

pd.set_option('plotting.backend', 'altair')

那么我将需要顶级 altair 包来定义https://github.com/pandas-dev/pandas/blob/master/pandas/plotting/_core.py 中的所有函数

如果我理解正确,这意味着我无法使pd.set_option('plotting.backend', 'altair')正常工作,而无需像 matplotlib 当前硬编码的方式那样在 pandas 中对 altair 包进行硬编码,对吗?

https://github.com/pandas-dev/pandas/blob/f1b9fc1fab93caa59aebcc738eed7813d9bd92ee/pandas/plotting/_core.py#L1550 -L1551

如果是这样,我强烈建议重新考虑在第三方包中公开此 API 的方式。

我建议的解决方案是采用基于入口点的框架,例如,它可以让我创建一个像altair_pandas这样的包,它注册altair入口点来实现 API。 否则,用户将永远对pd.set_option('plotting.backend', 'altair')没有按照他们的期望行事感到困惑。

同意。 我认为切入点是要走的路。 我会做一些原型。

2019 年 7 月 19 日星期五下午 1:16 Jake Vanderplas通知@ github.com
写道:

现在更仔细地观察:如果我理解正确,那么
绘图后端将使用:

pd.set_option('plotting.backend', 'name_of_module')

那么,我的理解是,如果我想做以下工作:

pd.set_option('plotting.backend', 'altair')

那么我将需要顶级的 altair 包来定义所有的功能

https://github.com/pandas-dev/pandas/blob/master/pandas/plotting/_core.py。
我不想用所有这些来污染 Altair 的顶级命名空间
额外的 API。 事实上,我更喜欢 altair 的 pandas 扩展
存在于一个单独的包中,因此它与发布节奏无关
牛郎星本身。

如果我理解正确,这意味着我无法制作 pd.set_option('plotting.backend',
'altair') 无需在 pandas 中对 altair 包进行硬编码即可正常工作
matplotlib 目前是硬编码的,对吗?

如果是这样,我强烈建议重新考虑如何实现这一点
第三方包。 特别是,采用基于入口点的框架
会让我创建一个像 altair_pandas 这样的包来注册 altair
入口点。 否则用户将永远对 pd.set_option('plotting.backend',
'altair') 不符合他们的预期。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看
https://github.com/pandas-dev/pandas/issues/26747?email_source=notifications&email_token=AAKAOITQM7HH5X4SZ4IAPS3QAIAIBA5CNFSM4HWIMEK2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2ML5OQ#issuecomment-513326778
或静音线程
https://github.com/notifications/unsubscribe-auth/AAKAOISFLHDGXLGQ3PUMNLDQAIAIBANCNFSM4HWIMEKQ
.

曾几何时,您所说的大部分是正确的,但现在情况不再如此。

如果你想要pandas.options.plotting.backend = 'altair' ,在 0.25 你只需要有一个函数altair.plot() 。 在某些时候,我认为调用函数pandas_plot而不是简单的plot会更好,因此它在具有其他功能的后端中是特定的,但我们最终没有进行更改。

如果在 altair 的顶层创建plot函数有问题,我们可以在以后的版本中重命名它,或者您也可以使用altair.pandas.plot ,但是用户必须设置pandas.options.plotting.backend = 'altair.pandas'

一旦用户执行import altair您当然可以自己更改选项。 我们可以实现一个后端注册表。 但是我认为如果用户执行pandas.options.plotting.backend = 'altair'并且失败了,那会让用户感到困惑,因为他们之前忘记了import altair

最后一件事是考虑我们可能为 altair(或任何其他可视化库)实现了多个 Pandas 后端。 所以,对我来说,后端的名称不是altair ,不一定是坏事。

这是一个基于入口点的实现

diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py
index 0610780ed..c8ac12901 100644
--- a/pandas/plotting/_core.py
+++ b/pandas/plotting/_core.py
@@ -1532,8 +1532,10 @@ class PlotAccessor(PandasObject):

         return self(kind="hexbin", x=x, y=y, C=C, **kwargs)

+_backends = {}

-def _get_plot_backend(backend=None):
+
+def _get_plot_backend(backend="matplotlib"):
     """
     Return the plotting backend to use (e.g. `pandas.plotting._matplotlib`).

@@ -1546,7 +1548,14 @@ def _get_plot_backend(backend=None):
     The backend is imported lazily, as matplotlib is a soft dependency, and
     pandas can be used without it being installed.
     """
-    backend_str = backend or pandas.get_option("plotting.backend")
-    if backend_str == "matplotlib":
-        backend_str = "pandas.plotting._matplotlib"
-    return importlib.import_module(backend_str)
+    import pkg_resources  # slow import. Delay
+    if backend in _backends:
+        return _backends[backend]
+
+    for entry_point in pkg_resources.iter_entry_points("pandas_plotting_backends"):
+        _backends[entry_point.name] = entry_point.load()
+
+    try:
+        return _backends[backend]
+    except KeyError:
+        raise ValueError("No backend {}".format(backend))
diff --git a/setup.py b/setup.py
index 53e12da53..d2c6b18b8 100755
--- a/setup.py
+++ b/setup.py
@@ -830,5 +830,10 @@ setup(
             "hypothesis>=3.58",
         ]
     },
+    entry_points={
+        "pandas_plotting_backends": [
+            "matplotlib = pandas:plotting._matplotlib",
+        ],
+    },
     **setuptools_kwargs
 )

我觉得还不错。 第 3 方软件包将修改它们的 setup.py(或 pyproject.toml)以包含类似的内容

entry_points={
    "pandas_plotting_backends": ["altair = pdvega._pandas_plotting_backend"]
}

我喜欢它打破命名和实现之间的紧密耦合。

我没有使用入口点,它们像 Python 环境的全局注册表吗? 作为他们的新手,我不喜欢这个想法,但我想那将是一个合理的方法。

我仍然希望同时拥有这两个选项,因此如果用户执行pandas.options.plottting.backend = 'my_own_project.my_custom_small_backend'则它可以工作,并且不需要创建包和设置入口点。

我没有使用入口点,它们像 Python 环境的全局注册表吗?

我也没有使用它们,但我认为这就是想法。 据我了解,它们来自 setuptools(但是像 flit 这样的包被钩住了?)。 所以它们不是标准库的一部分,但 setuptools 是每个人都使用的。

我还是想同时拥有这两种选择

回到import_module(backend_name)似乎是合理的。

此页面是否有帮助?
0 / 5 - 0 等级