-
-
Notifications
You must be signed in to change notification settings - Fork 18.5k
PLOT: Add option to specify the plotting backend #26753
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
776e82d
7d89c5e
fd36e1a
3ae0662
57f0119
06e829c
f5233f3
f7c6e33
1095344
e832985
b13a74b
001c57b
231094e
aa27d34
f31fc67
1f4e1c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,8 @@ | |
module is imported, register them here rather then in the module. | ||
|
||
""" | ||
import importlib | ||
|
||
import pandas._config.config as cf | ||
from pandas._config.config import ( | ||
is_bool, is_callable, is_instance_factory, is_int, is_one_of_factory, | ||
|
@@ -460,6 +462,40 @@ def use_inf_as_na_cb(key): | |
# Plotting | ||
# --------- | ||
|
||
plotting_backend_doc = """ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One question: If I wanted to use the altar backend, I would be more like to use I think hvplot will just be hvplot, so that's fine. Anyway, we might consider adding a dict here like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see your point, and I think it'd add value to the users, but not sure if I'm in favor of adding the extra complexity it's needed to manage aliases in a dynamic way. I like the simplicity of the parameter being the name of the module. I guess in some cases will look nicer than others. May be In practice I guess backends will register themselves, and users will rarely switch backends manually. But I guess if they do, it'll be better if they know they need to use the name of the module: import pandas
import hvplot.pandas
df.plot()
pandas.set_option('backend.plotting', 'matplotlib')
df.plot()
pandas.set_option('backend.plotting', 'hvplot.pandas')
df.plot() I don't have a strong opinion, but I'd say let's start with the simplest option, and add aliases or something else if we think it's useful once we start using this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it especially complex? I was thinking something like _plotting_aliases = {} # or define somewhere else
def register_plotting_backend_cb(key):
backend_str = cf.get_option(key)
backend_str = _plotting_aliases.get(backend_str, backend_str)
... Indeed, I think this simplifies things already, since we can use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What I wouldn't do is to have the aliases in pandas itself. May be I'm being too strict, but if feels wrong. But you're right, it's probably not as complex as I was thinking anyway. An simple option pandas.set_option('plotting.aliases', dict(pandas.get_option('plotting.aliases'), hvplot='hvplot.pandas')) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. but better in a follow up PR I think, so we can focus there on the exact syntax and approach There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perfectly fine doing as a followup. And my thinking may have been a bit muddled here. I was thinking that the backend library would have already been imported, and so would have a chance to register their own aliases. But as you say, it would be pandas managing them, which doesn't feel quite right. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. another simple option is that backends add an optional attribute if hasattr(backend_mod, 'alias'):
plotting_aliases[alias] = backend_mod.__name__ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes good idea. But still leaving this as a followup? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I prefer to keep the focus, the smaller the PRs, the better the content :) |
||
: str | ||
The plotting backend to use. The default value is "matplotlib", the | ||
backend provided with pandas. Other backends can be specified by | ||
prodiving the name of the module that implements the backend. | ||
""" | ||
|
||
|
||
def register_plotting_backend_cb(key): | ||
backend_str = cf.get_option(key) | ||
if backend_str == 'matplotlib': | ||
try: | ||
import pandas.plotting._matplotlib # noqa | ||
except ImportError: | ||
raise ImportError('matplotlib is required for plotting when the ' | ||
'default backend "matplotlib" is selected.') | ||
else: | ||
return | ||
|
||
try: | ||
TomAugspurger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
importlib.import_module(backend_str) | ||
except ImportError: | ||
raise ValueError('"{}" does not seem to be an installed module. ' | ||
'A pandas plotting backend must be a module that ' | ||
'can be imported'.format(backend_str)) | ||
|
||
|
||
with cf.config_prefix('plotting'): | ||
cf.register_option('backend', defval='matplotlib', | ||
TomAugspurger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
doc=plotting_backend_doc, | ||
validator=str, | ||
cb=register_plotting_backend_cb) | ||
|
||
|
||
register_converter_doc = """ | ||
: bool | ||
Whether to register converters with matplotlib's units registry for | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import pytest | ||
|
||
import pandas | ||
|
||
|
||
def test_matplotlib_backend_error(): | ||
msg = ('matplotlib is required for plotting when the default backend ' | ||
'"matplotlib" is selected.') | ||
try: | ||
import matplotlib # noqa | ||
except ImportError: | ||
with pytest.raises(ImportError, match=msg): | ||
pandas.set_option('plotting.backend', 'matplotlib') | ||
|
||
|
||
def test_backend_is_not_module(): | ||
msg = ('"not_an_existing_module" does not seem to be an installed module. ' | ||
'A pandas plotting backend must be a module that can be imported') | ||
with pytest.raises(ValueError, match=msg): | ||
pandas.set_option('plotting.backend', 'not_an_existing_module') | ||
|
||
|
||
def test_backend_is_correct(monkeypatch): | ||
monkeypatch.setattr('pandas.core.config_init.importlib.import_module', | ||
lambda name: None) | ||
pandas.set_option('plotting.backend', 'correct_backend') | ||
assert pandas.get_option('plotting.backend') == 'correct_backend' | ||
|
||
# Restore backend for other tests (matplotlib can be not installed) | ||
try: | ||
pandas.set_option('plotting.backend', 'matplotlib') | ||
except ImportError: | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"that" -> "than"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have any alternative engines to list here yet, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not at the moment, but that's a good point. Next week once this is merged I'm planning to work with few people to adapt
hvplot
. So we can see that everything is working well, and we can fix anything before 0.25. It may make sense to update this and usehvplot
as an example when it's ready.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great. I think this should be a prominent new feature if we are able to get either or both of pdvega ready to use it in time for the release.