Repository: quantumlib/Cirq

Issue:
Windows build flake related to tkinter and plotting
Happened in https://travis-ci.com/quantumlib/Cirq/jobs/244924672 (now rerun)

```
_____________________________ test_kak_plot_empty _____________________________
    def test_kak_plot_empty():
>       cirq.scatter_plot_normalized_kak_interaction_coefficients([])
cirq\linalg\decompositions_test.py:233: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cirq\linalg\decompositions.py:601: in scatter_plot_normalized_kak_interaction_coefficients
    fig = plt.figure()
c:\python37\lib\site-packages\matplotlib\pyplot.py:545: in figure
    **kwargs)
c:\python37\lib\site-packages\matplotlib\backend_bases.py:3252: in new_figure_manager
    return cls.new_figure_manager_given_figure(num, fig)
c:\python37\lib\site-packages\matplotlib\backends\_backend_tk.py:950: in new_figure_manager_given_figure
    window = tk.Tk(className="matplotlib")
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <tkinter.Tk object .>, screenName = None, baseName = 'pytest'
className = 'matplotlib', useTk = 1, sync = 0, use = None
    def __init__(self, screenName=None, baseName=None, className='Tk',
                 useTk=1, sync=0, use=None):
        """Return a new Toplevel widget on screen SCREENNAME. A new Tcl interpreter will
            be created. BASENAME will be used for the identification of the profile file (see
            readprofile).
            It is constructed from sys.argv[0] without extensions if None is given. CLASSNAME
            is the name of the widget class."""
        self.master = None
        self.children = {}
        self._tkloaded = 0
        # to avoid recursions in the getattr code in case of failure, we
        # ensure that self.tk is always _something_.
        self.tk = None
        if baseName is None:
            import os
            baseName = os.path.basename(sys.argv[0])
            baseName, ext = os.path.splitext(baseName)
            if ext not in ('.py', '.pyc'):
                baseName = baseName + ext
        interactive = 0
>       self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
E       _tkinter.TclError: Can't find a usable init.tcl in the following directories: 
E           {c:\python37\tcl\tcl8.6}
E       
E       c:/python37/tcl/tcl8.6/init.tcl: couldn't read file "c:/python37/tcl/tcl8.6/init.tcl": No error
E       couldn't read file "c:/python37/tcl/tcl8.6/init.tcl": No error
E           while executing
E       "source c:/python37/tcl/tcl8.6/init.tcl"
E           ("uplevel" body line 1)
E           invoked from within
E       "uplevel #0 [list source $tclfile]"
E       
E       
E       This probably means that Tcl wasn't installed properly.
c:\python37\lib\tkinter\__init__.py:2023: TclError
```


Discussion:
For tests it's a good idea to configure matplotlib to use a "headless" backend like "Agg". It can avoid a lot of issues like this (also avoid spurious windows popping up on dev machines when tests are run locally).
I just ran this test on my ubuntu subsystem for windows with gui-backend disabled and this test in addition to two others failed. The failing tests were:
In linalg/decompositions_test.py:
test_kak_plot_empty
test_scatter_plot_normalized_kak_interaction_coefficients
In cross_entropy_benchmarking_test.py:
test_cross_entropy_benchmarking

All of them failed with "_tkinter.TclError: couldn't connect to display ":0"". I hadn't previously attempted testing with the gui disabled so this hadn't come up before. I ran these two files in pytest on a native windows environment and the cross entropy benchmarking test opens a spurious window but the decomposition tests do not appear to. I hadn't noticed these before as the window closes itself before the testing is done and I had only ever looked at the results. 

Resolving patch:
diff --git a/cirq/conftest.py b/cirq/conftest.py
new file mode 100644
--- /dev/null
+++ b/cirq/conftest.py
@@ -0,0 +1,6 @@
+import matplotlib.pyplot as plt
+
+
+def pytest_configure(config):
+    # Use matplotlib agg backend which does not require a display.
+    plt.switch_backend('agg')


Test patch: