Repository: pyinstaller/pyinstaller

Issue:
ImportError: matplotlib is required for plotting when the default backend "matplotlib" is selected
I recently started to get this error with the latest pyinstaller from github (and also prod versions installed via pip): 

It only happens when I run the pyinstalled packaged version of my code. Any suggestions how this could be resolved? thanks
```

ImportError: matplotlib is required for plotting when the default backend "matplotlib" is selected.
Traceback (most recent call last):
  File "poker\gui\action_and_signals.py", line 275, in <lambda>
  File "poker\gui\action_and_signals.py", line 432, in update_strategy_analyser
  File "poker\gui\action_and_signals.py", line 446, in strategy_analyser_update_plots
  File "poker\gui\plots\bar_plotter_2.py", line 78, in drawfigure
  File "pandas\plotting\_core.py", line 892, in __call__
  File "pandas\plotting\_core.py", line 1814, in _get_plot_backend
  File "pandas\plotting\_core.py", line 1757, in _load_backend
ImportError: matplotlib is required for plotting when the default backend "matplotlib" is selected.
```


Discussion:
This seems to be just what the error is saying - `matplotlib` is not present in the frozen application (which uses default `pandas.plotting` backend).

Can you check if `build\<name>\Analysis-00.toc` lists any `matplotlib` modules? 
If not, check if the build log contains any `matplotlib` related messages (e.g., `Loading module hook 'hook-matplotlib.py' from ...`). 
If not, check if the environment from which you are running pyinstaller (which may or may not be the same as the one you use when you run source version of your code) has `matplotlib` installed?
Downgrading to pandas 1.2.4 resolved the issue.

On Sun, 11 Jul 2021 at 08:53, Rok Mandeljc ***@***.***> wrote:

> This seems to be just what the error is saying - matplotlib is not
> present in the frozen application.
>
> Can you check if build\<name>\Analysis-00.toc lists any matplotlib
> modules?
> If not, check if the build log contains any matplotlib related messages
> (e.g., Loading module hook 'hook-matplotlib.py' from ...).
> If not, check if the environment from which you are running pyinstaller
> (which may or may not be the same as the one you use when you run source
> version of your code) has matplotlib installed?
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub
> <https://github.com/pyinstaller/pyinstaller/issues/5994#issuecomment-877757573>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAJSW7SKKBHRGJQTD4RAH3TTXFEYHANCNFSM5AEVRWLQ>
> .
>

For others having the same issue and don't want to downgrade anything, you can add `import pandas.plotting._matplotlib` to resolve this. 

<hr>

If you're trying to use `plt.show()` you may get `UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.` Explicitly setting the `matplotlib` backend resolves this, however, you'll have to first explicitly import the backend from `matplotlib.backends` and then use it. 


```python
import matplotlib
import matplotlib.backends.backend_tkagg
matplotlib.use('tkagg')
```


Resolving patch:
diff --git a/PyInstaller/hooks/hook-pandas.plotting.py b/PyInstaller/hooks/hook-pandas.plotting.py
new file mode 100644
--- /dev/null
+++ b/PyInstaller/hooks/hook-pandas.plotting.py
@@ -0,0 +1,18 @@
+#-----------------------------------------------------------------------------
+# Copyright (c) 2021, PyInstaller Development Team.
+#
+# Distributed under the terms of the GNU General Public License (version 2
+# or later) with exception for distributing the bootloader.
+#
+# The full license is in the file COPYING.txt, distributed with this software.
+#
+# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
+#-----------------------------------------------------------------------------
+
+from PyInstaller.utils.hooks import is_module_satisfies
+
+# Starting with pandas 1.3.0, pandas.plotting._matplotlib is imported via importlib.import_module() and needs to be
+# added to hidden imports. But do this only if matplotlib is available in the first place (as it is soft dependency
+# of pandas).
+if is_module_satisfies('pandas >= 1.3.0') and is_module_satisfies('matplotlib'):
+    hiddenimports = ['pandas.plotting._matplotlib']


Test patch:
diff --git a/tests/functional/test_libraries.py b/tests/functional/test_libraries.py
--- a/tests/functional/test_libraries.py
+++ b/tests/functional/test_libraries.py
@@ -393,6 +393,24 @@ def test_pandas_io_formats_style(pyi_builder):
         """)
 
 
+@importorskip('pandas')
+@importorskip('matplotlib')
+def test_pandas_plotting_matplotlib(pyi_builder):
+    # Test that pandas.plotting works. Starting with pandas 1.3.0, the used pandas.plotting._matplotlib backend module
+    # is loaded via importlib.import_module(), and needs a hidden import. See #5994.
+    pyi_builder.test_source(
+        """
+        import matplotlib as mpl
+        import pandas as pd
+
+        mpl.use('Agg')  # Use headless Agg backend to avoid dependency on display server.
+
+        series = pd.Series([0, 1, 2, 3], [0, 1, 2, 3])
+        series.plot()
+        """
+    )
+
+
 @importorskip('win32ctypes')
 @pytest.mark.skipif(not is_win, reason='pywin32-ctypes is supported only on Windows')
 @pytest.mark.parametrize('submodule', ['win32api', 'win32cred', 'pywintypes'])