Pandas: API: определение API для панд, строящих бэкенды

Созданный на 9 июн. 2019  ·  44Комментарии  ·  Источник: pandas-dev/pandas

В # 26414 мы разделили модуль построения графиков pandas на общую структуру построения графиков, способную вызывать различные бэкэнды и текущие бэкэнды matplotlib. Идея состоит в том, что другие бэкенды могут быть реализованы более простым способом и использоваться с общим API пользователями pandas.

API, определенный текущим бэкэндом matplotlib, включает объекты, перечисленные далее, но этот API, вероятно, можно упростить. Вот список вопросов / предложений:

Неоспоримые методы для сохранения в API (они предоставляют функциональность Series.plot(kind='line') ...):

  • LinePlot
  • BarPlot
  • BarhPlot
  • HistPlot
  • BoxPlot
  • KdePlot
  • Площадь
  • PiePlot
  • Точечная диаграмма
  • HexBinPlot

Функции построения графиков, представленные в пандах (например, pandas.plotting.andrews_curves(df) )

  • andrews_curves
  • autocorrelation_plot
  • bootstrap_plot
  • lag_plot
  • parallel_coordinates
  • Радвиз
  • 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://github.com/python-sprints/pandas_plotting_library/blob/master/AllPlottingExamples.ipynb

CC: @ 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
 )

Думаю, это неплохо. Сторонние пакеты изменят свой setup.py (или pyproject.toml), чтобы включить что-то вроде

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

Мне нравится, что это нарушает тесную связь между именованием и реализацией.

Все 44 Комментарий

Я думаю, что такие вещи, как автокорреляция, должны быть исключены из заменяемого внутреннего API.

Я думаю, что мы оставили такие вещи, как df.boxplot и hist, потому что их поведение немного отличается от API .plot. Я бы не рекомендовал делать их частью серверного API.

Вот мое начало работы с предложенным серверным API несколько месяцев назад: https://github.com/TomAugspurger/pandas/commit/b07aba28a37b0291fd96a1f571848a7be2b6de8d

Я думаю, стоит упомянуть, что по крайней мере hvplot (остальные не проверял) уже предоставляет такие функции, как andrews_curves , scatter_matrix , lag_plot ..

Может быть, если мы не хотим заставлять все бэкенды реализовывать их, мы можем проверить, реализует ли их выбранный бэкэнд, и по умолчанию использовать графики matplotlib?

Я предположил, что boxplot и hist вели себя точно так же, но только что у них были ярлыки Series.hist() для Series.plot.hist() . «Ярлык» показывает сетку сюжета, но кроме этого я не заметил никакой разницы.

ИМО, основным значением этой опции является пространство имен .plot .

Если пользователям нужен график кривой Эндрю на hvplot, им следует импортировать функцию
из hvplot и передайте туда фрейм данных.

В воскресенье, 9 июня 2019 г., в 7:17 Марк Гарсия [email protected] написал:

Думаю, стоит упомянуть, что хотя бы hvplot (не проверял
rest) уже предоставляет такие функции, как andrews_curves,
scatter_matrix, lag_plot, ...

Может быть, если мы не хотим заставлять все бэкенды реализовывать их, мы можем
проверьте, реализует ли их выбранный бэкэнд, и по умолчанию
графики matplotlib?

Я предположил, что boxplot и hist ведут себя одинаково, но только что
ярлыки Series.hist () для Series.plot.hist (). "Ярлык" показывает
сюжетная сетка, но кроме этого я не заметил никакой разницы.

-
Вы получаете это, потому что находитесь в упомянутой команде.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/pandas-dev/pandas/issues/26747?email_source=notifications&email_token=AAKAOIRLJHBMXMXKK2IG2NDPZTYFPA5CNFSM4HWIMEK2YY3PNVWWK3TUL52-53DVMVREXWO3TUL52HS4DFMVREXWOFW08B0B0B0B0B0B0B0B0B08
или отключить поток
https://github.com/notifications/unsubscribe-auth/AAKAOISDHL6H7PVOOJAQXELPZTYFPANCNFSM4HWIMEKQ
.

Я думаю, это имеет смысл, но если мы это сделаем, я думаю, нам следует переместить их в pandas.plotting.matplotlib.andrews_curves вместо pandas.plotting.andrews_curves .

@TomAugspurger Мне нужно проверить более подробно, но я думаю, что API, который вы реализовали в https://github.com/TomAugspurger/pandas/commit/b07aba28a37b0291fd96a1f571848a7be2b6de8d , имеет больше смысла. Я поработаю над ним, как только закончу # 26753. Я также поэкспериментирую, возможно ли переместить andrews_curves , scatter_matrix ... на синтаксис .plot() , я думаю, это упростит и упростит задачу для всех (нас , сторонние библиотеки и пользователи).

Что здесь подразумевается в отношении дополнительных kwargs, переданных функциям построения графиков? Должны ли дополнительные серверные модули пытаться дублировать функциональность всех настроек графика в стиле matplotlib или они должны разрешать передачу ключевых слов, соответствующих тем, которые используются конкретным сервером?

Первый вариант был бы хорош в теории, но потребовал бы, чтобы каждый бэкэнд построения графиков, не являющийся matplotlib, по существу реализовал свой собственный уровень преобразования matplotlib с длинным хвостом несовместимости, который по сути никогда не будет полным (если говорить по опыту человека, который пытался создать mpld3, лет назад).

Второй вариант не так хорош с точки зрения взаимозаменяемости, но позволяет добавлять другие серверные модули с более разумным набором ожиданий.

Я думаю, что это зависит от того, что они с ними делают. Достижение 100%
совместимость между бэкэндами на самом деле невозможна,
так как возвращаемый тип больше не будет Axes matplotlib. И если
мы несовместимы по типу возврата, я не думаю, что бэкенды
должен наклониться назад, чтобы попытаться обработать все возможные аргументы ключевого слова.

Поэтому я думаю, что панды должны задокументировать, что **kwargs будет передано в
базовый движок построения, и они могут делать все, что им заблагорассудится, с
их.

В понедельник, 10 июня 2019 г., в 10:42 Джейк Вандерплас [email protected]
написал:

Какое здесь намерение относительно дополнительных кваргов, переданных на построение?
функции? Если дополнительные серверные части попытаются дублировать
функциональность всех настроек графика в стиле matplotlib, или если они
разрешить передачу ключевых слов, которые соответствуют тем, которые используются конкретным
бэкэнд?

Первый вариант был бы хорош в теории, но потребовал бы
не-matplotlib, строящий бэкэнд, чтобы по существу реализовать свой собственный matplotlib
слой преобразования с длинным хвостом несовместимости, который
по сути, никогда не быть полным (исходя из опыта человека,
несколько лет назад пробовал создать mpld3).

Второй вариант не так хорош с точки зрения
взаимозаменяемость, но позволит добавлять другие серверные модули с более
разумный набор ожиданий.

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/pandas-dev/pandas/issues/26747?email_source=notifications&email_token=AAKAOIS3IBV4XSSY7BPSCF3PZZY5LA5CNFSM4HWIMEK2YY3PNVWWK3TUL52HS4DFMVREXW4
или отключить поток
https://github.com/notifications/unsubscribe-auth/AAKAOIQ3GYOGAPUZ4LSNK2DPZZY5LANCNFSM4HWIMEKQ
.

Прошу прощения, если это глупый вопрос, но если вы определите «API» построения графиков, который в основном представляет собой группу стандартных графиков, не будет ли каждый бэкэнд производить более или менее одинаковый результат? какие новые возможности это означает? что-то вроде панд для экспортера веги?

Я не думаю, что правильно говорить, что каждый бэкэнд производит более или менее одинаковый результат.

Например, matplotlib действительно хорош для статических диаграмм, но не очень хорош для создания портативных интерактивных диаграмм.

С другой стороны, боке, альтаир и др. отлично подходят для интерактивных диаграмм, но не так развиты, как matplotlib для статических диаграмм.

Возможность производить и то, и другое с одним и тем же API было бы большим выигрышем.

Первый вариант был бы хорош в теории, но потребовал бы, чтобы каждый бэкэнд построения графиков, не являющийся matplotlib, по существу реализовал свой собственный уровень преобразования matplotlib с длинным хвостом несовместимости, который по сути никогда не будет полным (если говорить по опыту человека, который пытался создать mpld3, лет назад).

а также закрепляет Matplotlib даже больше, чем мы уже знаем API. Я думаю, что для панд имеет смысл объявить, какие ручки стиля они хотят раскрыть, и ожидать, что серверные реализации разберутся, что это означает. Это может означать _не_ слепую передачу **kwargs а вместо этого обеспечение того, чтобы возвращаемые объекты были «правильными» для заданного бэкэнда, чтобы иметь возможность выполнять настройку стиля постфактум.

Например, matplotlib действительно хорош для статических диаграмм, но не очень хорош для создания портативных интерактивных диаграмм.

Спасибо @jakevdp , да, поддержка интерактивных диаграмм - хорошая цель.

Прежде чем что-то зайдет слишком далеко по этому проспекту, вот альтернативное решение.

Вместо того, чтобы объявлять API-интерфейс pandas plotting теперь спецификацией и просить пакеты viz реализовать его специально, почему бы не сгенерировать промежуточное представление (например, файл vega JSON) графика и побудить бэкенды использовать его в качестве входных данных.

Преимущества включают:

  1. Не привязан к выразительной силе овеществленного API pandas, который не был разработан как спецификация.
  2. Работа, проделанная путем построения пакетов для поддержки pandas, становится доступной для других пакетов pydata, которые генерируют IR.
  3. Продвижение общего языка для визуализации обмена в пространстве pydata
  4. Это делает новый инструмент более мощным, поскольку он более широко применим.
  5. Что делает усилия по их написанию более разумными. В основном улучшенные стимулы.

Vega / Vega-lite , как современный, устоявшийся, открытый и основанный на JSON язык спецификаций визуализации, несколько человеко-лет вложили его в разработку и реализацию, и существующие инструменты, построенные на его основе, похоже, были созданы специально для этой цели. . (только, пожалуйста, не надо ).

Вы знаете, frontend->IR->backend , вроде как созданы компиляторы.

По крайней мере, три пакета уже реализуют API. Все, что нужно сделать pandas, - это предложить вариант изменения бэкэнда и задокументировать его использование, что кажется хорошей выгодой для наших денег.

15 июня 2019 г., в 16:28, pilkibun [email protected] написал:

Например, matplotlib действительно хорош для статических диаграмм, но не очень хорош для создания портативных интерактивных диаграмм.

Спасибо @jakevdp , да, поддержка интерактивных диаграмм - хорошая цель.

Прежде чем что-то зайдет слишком далеко по этому проспекту, вот альтернативное решение.

Вместо того, чтобы объявлять API-интерфейс pandas plotting теперь спецификацией и просить пакеты viz реализовать его специально, почему бы не сгенерировать промежуточное представление (например, файл vega JSON) графика и побудить бэкенды использовать его в качестве входных данных.

Преимущества включают:

Не привязан к выразительной силе овеществленного API pandas, который не был разработан как спецификация.
Работа, проделанная путем построения пакетов для поддержки pandas, становится доступной для других пакетов pydata, которые генерируют IR.
Продвижение общего языка для визуализации обмена в пространстве pydata
Это делает новый инструмент более мощным, поскольку он более широко применим.
Что делает усилия по их написанию более разумными. В основном улучшенные стимулы.
Vega / Vega-lite, как современный, устоявшийся, открытый и основанный на JSON язык спецификаций визуализации, несколько человеко-лет вложили его в разработку и реализацию, и существующие инструменты, построенные на его основе, похоже, были созданы специально для этой цели. . (только, пожалуйста, не надо).

Вы знаете, фронтенд-> ИК-> бэкэнд, как и компиляторы, созданы.

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub или отключите обсуждение.

Теперь мы объединили # 26753, и бэкэнд построения можно изменить с pandas. Когда мы разделяем код matplotlib, мы оставили SeriesPlotMethods и FramePlotMethods на стороне pandas (не matplotlib). Это было в основном для того, чтобы оставить строки документации на стороне панд.

Но я вижу, что то, что сделали бэкенды, было переопределением этих классов. Итак, в настоящее время мы ожидаем, что у бэкэндов будет один класс для каждого графика (например, LinePlot , BarPlot ), но вместо этого они реализуют класс с графиком для каждого метода (например, hvPlot, or the same names as pandas for pdvega `).

Я думаю, что имеет смысл, по крайней мере, в первой версии, что мы реализуем API так, как это сделали hvplot и pdvega . Я бы просто создал абстрактный класс в пандах, от которого наследуются бэкенды.

Если это имеет смысл для всех, я начну с создания абстрактного класса и адаптации бэкэнда matplotlib, который у нас есть в pandas, и как только это будет сделано, мы адаптируем hvplot и pdvega (изменения там должно быть совсем мало).

Мысли?

Я думаю, что имеет смысл, по крайней мере, в первой версии, что мы реализуем API, как это сделали hvplot и pdvega. Я бы просто создал абстрактный класс в пандах, от которого наследуются бэкенды.

Я думаю, что в итоге такой подход будет чище. Я не могу разговаривать с другими серверными модулями построения графиков, но, по крайней мере, в hvPlot разные методы построения графиков используют довольно много кода, например, scatter , line и area во многом аналогичны, и Я бы предпочел не полагаться на создание подклассов для совместного использования кода между ними. Кроме того, я думаю, что у разных бэкэндов должна быть возможность добавлять дополнительные типы графиков, и использование их в качестве дополнительных общедоступных методов кажется самым простым и естественным подходом.

Просто чтобы убедиться, что я понимаю, когда вы говорите I'd prefer not to rely on subclassing to share code between them вы имеете в виду как в class LinePlot(MPLPlot) , верно? А разве вы не думаете, что наследовать от абстрактного базового класса - плохая идея?

Я думаю, что я +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 является модулем (может быть pdvega , altair , altair.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 . Это не обязательно должно быть правдой, и у пользователей возникает неверное впечатление, что вы строите напрямую с боке, а не с пандами, строящими бэкэнд для боке.

@datapythonista спасибо за подробный ответ. Я готов оставить его сейчас, как и в первоначальном выпуске (возможность псевдонима всегда может быть добавлена ​​позже).

Если пользователям нужен график кривой Эндрю в hvplot, они должны импортировать функцию из hvplot и передать туда фрейм данных.

+1, я бы тоже не стал выставлять все дополнительные функции построения графиков через бэкэнд.

Но что касается перемещения их в pandas.plotting.matplotlib , мне это кажется ненужным разрывом с обратной несовместимостью (при условии, что вы имели в виду не только перемещение реализации).

pandas.set_option ('plotting.backend', 'bokeh') будет работать, только если был вызван import pandas_bokeh, и будет сбивать с толку пользователей.

Если мы используем точки входа для регистрации расширений, то это не обязательно: установка пакета в системе зарегистрирует точку входа и сделает ее видимой для pandas. Например, это то, что использует Altair для обнаружения различных средств визуализации, которые мог установить пользователь.

Кроме того, что бы это ни стоило, как только это войдет, я бы, вероятно, отказался от pdvega и переместил соответствующий код в новый пакет с именем pandas_altair или что-то подобное.

@datapythonista Я думаю, нам следует определиться с объемом API-интерфейса построения графиков до версии 0.25.0 (но не для RC).

Вы за сохранение различных функций построения графиков (а также hist / boxplot)?

@datapythonista закрыть это как мы слили PR?

@jreback Я бы @TomAugspurger и @jorisvandenbossche не хотели делегировать

Что бы я сделал для рисования панд - дальше будет бэкэнд.

Для выпуска:

  • Оставьте все как есть, hvplot реализует все сюжеты, как от аксессоров, так и тех, которые нет. И я считаю, что делегирование всего упрощает задачу.
  • Не уверен, что исключил бы из вышесказанного register_converters. По крайней мере, мы должны изменить имя с register_matplotlib_converters , если мы их делегируем

Для следующего выпуска:

  • Я бы отказался от всех дубликатов pandas.plotting.boxplot , Series.hist , ...
  • Я бы переместил все графики для вызова из аксессоров (andrew_curves, radviz, parallel_curves, ...).

Для первоначального выпуска API серверной части я бы предпочел быть более консервативным в том, что мы представляем, чем включать все. Позже добавить вещи намного проще, чем убрать.

Я бы лично также не переносил все эти разные графики в аксессор (могут быть некоторые исключения, например, матрица разброса), IMO, andrew_curves и radviz и т.д. не "стоят" метода.

Тем не менее: хотим ли мы, чтобы серверные части могли реализовывать дополнительные «виды»? Так что нам не нужно решать, как панды, какие именно методы доступа могут быть доступны. Если пользователь передает определенный kind или пытается получить доступ к атрибуту, мы все равно можем передать его в бэкэнд plot с пользовательским __getattribute__ .

Просто чтобы немного объяснить, почему дела обстоят так, как сейчас. Это актуально, потому что я не совсем уверен, как реализовать предлагаемые вами изменения или не раскрывать вещи в целом. Я не говорю здесь, что это нельзя сделать по-другому, просто чтобы обогатить дискуссию.

Первым решением было переместить весь код, использующий matplotlib, в отдельный модуль ( pandas.plotting._matplotlib ). Таким образом, этот модуль каким-то образом стал серверной частью matplotlib.

Все, что было общедоступным в pandas.plotting осталось там как общедоступное. И чтобы упростить задачу, каждая из этих функций после вызова загружает бэкэнд (вызов _get_plot_backend ) и вызывает там функцию.

Общедоступный API для пользователя не претерпел никаких изменений, пользователям по-прежнему доступны те же методы и функции. Мы не раскрываем ничего нового.

Насколько я понимаю, если мы решим, что существующий сюжет, такой как andrew_curves , не делегирован бэкэнду, это означает, что вместо того, чтобы выбирать бэкэнд пользователем, мы все равно выберем бэкэнд matplotlib. Учитывая, что как минимум hvplot уже реализует andrew_curves , я лично не вижу в этом смысла. Если пользователю нужен график andrew_curves в matplotlib, это так же просто, как не менять бэкэнд (или устанавливать его снова, если он был изменен). Итак, с этим изменением мы просто сделаем жизнь пользователей намного сложнее, добавив дополнительную сложность пандам.

Если мы хотим быть вежливыми с разработчиками бэкэнда и не заставлять их реализовывать графики, которые могут быть не такими популярными (я думаю, это одна из причин?), Может быть, мы можем по умолчанию использовать бэкэнд matplotlib для всего, что отсутствует в выбранном бэкэнде ?

Что касается делегирования какого-либо неизвестного вида сюжета бэкэнду, я делаю это прямо сейчас. Конечно, рано или поздно это обретет смысл. Но я думаю, что иметь несколько типов сюжетов, задокументированных в пандах, и иметь дополнительные, которые мы не документируем, кажется немного взломанным. Я думаю, что можно дождаться следующей версии, после того, как мы получим отзывы о том, как разные бэкенды работают для пользователей, и у нас будет больше времени для подробного обсуждения и анализа.

Если пользователю нужен график andrew_curves в matplotlib, это так же просто, как не менять бэкэнд (или снова устанавливать его, если он был изменен). Итак, с этим изменением мы просто сделаем жизнь пользователей намного сложнее, добавив дополнительную сложность пандам.

Не думаю, что мы усложнили бы жизнь пользователю. Вместо того, чтобы импортировать его из pandas.plotting, если им нужна версия hvplot, они могут просто импортировать ее оттуда. Это невозможно для метода DataFrame.plot, поскольку он определен для объекта. Для меня это основная причина создания бэкэнда.

Если мы хотим быть вежливыми с разработчиками серверной части, а не заставлять их реализовывать сюжеты, которые могут быть не такими популярными

Для меня это не о том, чтобы быть милым или что потребуется реализовать все (это совершенно нормально, если бэкэнд не поддерживает все типы построения графиков, ИМО), а скорее ненужное расширение API бэкенда построения графиков, которое также связывает нас с ним .
Если бы мы перезапустили pandas с нуля, я не думаю, что эти разные типы построения будут включены. Но с помощью API-интерфейса построения графиков мы в некотором роде начинаем что-то новое.

Есть другие мнения по этому поводу?

Согласен с @jorisvandenbossche.


Просто чтобы убедиться, что это не потеряно, я думаю, что предложение @jakevdp об использовании точек входа в setuptool стоит рассмотреть для решения проблемы регистрации заказа на импорт: https://github.com/pandas-dev/pandas/issues/26747 #issuecomment -507415929

@jorisvandenbossche, как бы вы это изменили в коде? Вместо того, чтобы определять бэкэнд в настройках для этих методов, получить бэкэнд matplotlib? Я думаю, что это концептуально неверно, но меня это устраивает, если есть согласие. Все, что отменяет развязку кода matplotlib от остального, я -1.

Поскольку вы упомянули, что в pandas с нуля мы не будем включать эти графики, следует ли нам отказаться от них? Я ставлю +1 на перенос всех графиков, которые не являются методами Series или DataFrame в сторонний пакет. Или, если какой-либо из них достаточно важен, чтобы его сохранить, переместить его для вызова с .plot() в качестве других.

я бы осуждал нестандартные сюжеты в пандах
и перейти во внешний пакет

Джорис ненадолго отключен.

Я думаю, что когда мы обсуждали это в прошлом, его и моя позиция по тезисам заключается в том, чтобы просто оставить их нетронутыми, пока они не превратятся в бремя обслуживания.

Так что мы находимся на одной странице, это краткое изложение того, что у нас есть, и мое понимание состояния обсуждения:

Используется как методы Series и DataFrame (мы все счастливы оставить их такими, какие они есть, делегированные выбранному бэкэнду):

  • Участок
  • boxplot_frame
  • boxplot_frame_groupby
  • hist_frame
  • hist_series

Другие графики (в стадии обсуждения, должны ли они быть устаревшими, делегированы бэкэнду matplotlib или делегированы выбранному бэкэнду):

  • коробчатый сюжет
  • scatter_matrix
  • Радвиз
  • andrews_curves
  • bootstrap_plot
  • parallel_coordinates
  • lag_plot
  • autocorrelation_plot
  • стол

Другие общедоступные материалы в pandas.plotting (тоже обсуждаются):

  • plot_params
  • register_matplotlib_converters
  • deregister_matplotlib_converters

Что касается раздела Other plots , я лично считаю, что они являются бременем обслуживания на данный момент, и я +1 за удаление их из pandas и осуждаю их в 0.25.

Что касается преобразователей и прочего, то то, что у нас есть сейчас, определенно неверно, поскольку register_matplotlib_converters делегирует выбранный график, который не может быть matplotlib. Я думаю, мы можем рассмотреть следующие варианты:

  • Переименуйте их в register_converters / deregister_converters , исключите текущие и продолжайте делегировать бэкэнд.
  • Переместите их из pandas.plotting в pandas.plotting.matplotlib (что будет означать, что бэкэнд matplotlib станет общедоступным, поэтому я бы не стал)
  • Оставьте их как есть и делегируйте бэкэнду matplotlib вместо выбранного бэкэнда (я рассматриваю это скорее как взлом, чем хорошее дизайнерское решение, я бы предпочел, чтобы pandas.plotting зависел от того, какие бэкенды существуют)

Что касается раздела «Другие сюжеты», я лично считаю, что на данный момент они являются обременительным бременем, и я ставлю +1 за их удаление из панд и осуждаю их в версии 0.25.

Как вы считаете «другие участки» обременительным бременем для обслуживания? Если посмотреть на историю «разных» графиков: https://github.com/pandas-dev/pandas/commit/0.24.x/pandas/plotting/_misc.py , с 2017 года у нас ~ 10-15 коммитов. большинство из них - это глобальная очистка, применяемая ко всей кодовой базе (так что небольшая маржинальная нагрузка). Я вижу только 1-2 коммитов, изменяющих документы, и никаких коммитов, меняющих функциональность.

Переименуйте их в register_converters / deregister_converters, исключите текущие и продолжайте делегировать бэкэнд

Не думаю, что в этом есть смысл. Существуют конвертеры для matplotlib, которые мы написали для matplotlib. У других бэкэндов их не будет. Вероятно, это не должно быть частью внутреннего API.

Я не имел в виду, что эти графики являются обузой из-за количества обслуживания, которое мы провели в последние месяцы лет, а из-за проблемы, которую они предполагают сейчас, в наличии последовательного и интуитивно понятного API для пользователей и хорошей модульной дизайн кода для нас.

Что касается конвертеров, я не знаю, могут ли авторы backend в некоторых случаях реализовать эквивалент для matplotlib. Но это не кажется проблемой, если они этого не делают, и эти функции ничего не делают для некоторых или всех других бэкэндов. Я тоже согласен с вариантом 2, но я не считаю его таким изящным.

но из-за проблемы, которую они предполагают сейчас, в наличии последовательного и интуитивно понятного API для пользователей и хорошей модульной конструкции кода для нас.

Однако они уже несколько несовместимы с DataFrame.plot. Название "разное" подразумевает это :) Имеет ли заменяемый бэкэнд это хуже? В какой степени это стоит оттока пользовательского кода? Я так не думаю.

Я не знаю, могут ли авторы backend в некоторых случаях реализовать аналогичные для matplotlib.

Я так не думаю. Смысл этих конвертеров - научить matplotlib об объектах pandas. Библиотеки, реализующие бэкэнд, не будут иметь этой проблемы, поскольку они уже зависят от pandas.

Лично я думаю об этом в основном с точки зрения управления сложностью. Наличие стандартного API построения графиков, делегированного серверной части через единый API, легко понять и поддерживать. Пользователи и Сопровождающие просто нужно узнать , что есть plot функция с kind аргумент, и что это будет выполняться в выбранном интерфейсе.

Наличие в бэкэнде набора разнородных графиков, которые, помимо того, что не следуют одному и тому же API, используют бэкэнд, но не тот, который выбран для других графиков, а один из Matplotlib, добавляет слишком много сложности для всех ИМХО.

И стоимость их перемещения мне кажется небольшой, я предполагаю, что не большая часть наших пользователей даже знает об этих графиках. А тем, кто это сделает, просто нужно будет установить дополнительный пакет conda и использовать import pandas_plotting; pandas_plotting.andrews_curves(df) вместо pandas.plotting.andrews_curves(df) .

Мне кажется, что можно много выиграть за небольшую цену, но, конечно, это всего лишь мнение.

Можем ли мы задокументировать, что заменяемый бэкэнд предназначен только для Series / DataFrame.plot? Это кажется довольно простым правилом.

Похоже на хакер, который добавляет мне ненужной сложности; Я не думаю, что объяснение этого в документации делает его менее интуитивно понятным.

Но в любом случае ничего страшного. Если это предпочтительный вариант, я бы реализовал его так, по крайней мере, увеличение сложности кода минимально: # 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. Я бы предпочел не засорять пространство имен верхнего уровня Altair всеми этими дополнительными API, которые не предназначены для использования пользователями Altair. Фактически, я бы предпочел, чтобы расширение altair pandas находилось в отдельном пакете, чтобы оно не было привязано к ритму выпуска самого Altair.

Если я правильно понимаю, это означает, что я не могу заставить pd.set_option('plotting.backend', 'altair') работать правильно без жесткого кодирования пакета altair в пандах, как в настоящее время жестко запрограммирован matplotlib, это правильно?

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') не делает того, чего они ожидают.

Согласовано. Я думаю, что точки входа - это то, что нужно. Я что-нибудь сделаю прототипом.

Пт, 19 июля 2019 г., в 13:16 Джейк Вандерплас [email protected]
написал:

Теперь посмотрим на это повнимательнее: если я правильно понимаю, то, как
будет установлен бэкэнд построения с использованием:

pd.set_option ('plotting.backend', 'имя_модуля')

Насколько я понимаю, если я хочу выполнить следующую работу:

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') работают правильно без жесткого кодирования пакета 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=AAKAOITQM7HH5X4SZ4IAPS3QAIAIBA5CNFSM4HWIMEK2YY3PNVWWK3TUL52HS4DFMVREXWG43
или отключить поток
https://github.com/notifications/unsubscribe-auth/AAKAOISFLHDGXLGQ3PUMNLDQAIAIBANCNFSM4HWIMEKQ
.

Был момент, когда то, что вы говорите, было в основном правильным, но это уже не так.

Если вы хотите pandas.options.plotting.backend = 'altair' , в 0.25 вам просто нужна функция altair.plot() . В какой-то момент я подумал, что было бы лучше вызвать функцию pandas_plot а не просто plot , поэтому она была специфичной для бэкэнда, у которого были другие функции, но мы, наконец, не внесли изменения.

Если создание функции plot на верхнем уровне altair является проблемой, мы можем переименовать ее в будущей версии, или вы также можете иметь altair.pandas.plot , но тогда пользователям придется установить pandas.options.plotting.backend = 'altair.pandas' .

Вы, конечно, можете изменить эту опцию самостоятельно, как только пользователи выполнят import altair . И мы могли бы реализовать реестр бэкэндов. Но я думаю, что пользователей будет сбивать с толку, если они сделают pandas.options.plotting.backend = 'altair' а это не удастся, потому что они забыли import altair раньше.

И последнее, что нужно учитывать, что мы могли бы иметь более одного бэкэнда pandas, реализованного для altair (или любой другой библиотеки визуализации). Так что для меня то, что имя бэкэнда не 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
 )

Думаю, это неплохо. Сторонние пакеты изменят свой 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 hook?). Таким образом, они не являются частью стандартной библиотеки, но setuptools все равно используются.

Я все еще хотел бы иметь оба варианта

Возврат к import_module(backend_name) кажется разумным.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги