Repository: Qiskit/qiskit

Issue:
MatplotlibDeprecationWarning: The M attribute was deprecated in Matplotlib 3.4
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra version**: 0.16.4
- **Python version**: 3.8.8
- **Operating system**: Ubuntu Linux

### What is the current behavior?

When running the Bloch sphere visualization function, the following warning message appears:
```
/opt/conda/lib/python3.8/site-packages/qiskit/visualization/bloch.py:69: MatplotlibDeprecationWarning: 
The M attribute was deprecated in Matplotlib 3.4 and will be removed two minor releases later. Use self.axes.M instead.
  x_s, y_s, _ = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
```

### Steps to reproduce the problem

```py
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_bloch_multivector

qc = QuantumCircuit(1)
state = Statevector.from_instruction(qc)
plot_bloch_multivector(state)
```


### What is the expected behavior?

No warning message


### Suggested solutions

Refactor mathplotlib related codes not to use deprecated feature.




Discussion:
This is something we tried to fix recently in https://github.com/Qiskit/qiskit-terra/pull/6087 (since the deprecation warnings broke CI). It looks like the only way we'll be able to fix all the deprecation warnings is if we bump the minimum matplotlib version to 3.4. I think we're likely going to wait to do this until the matplotlib 3.5 release forces us to.

Resolving patch:
diff --git a/qiskit/visualization/bloch.py b/qiskit/visualization/bloch.py
--- a/qiskit/visualization/bloch.py
+++ b/qiskit/visualization/bloch.py
@@ -50,6 +50,7 @@
 
 import os
 import numpy as np
+import matplotlib
 import matplotlib.pyplot as plt
 from matplotlib.patches import FancyArrowPatch
 from mpl_toolkits.mplot3d import Axes3D, proj3d
@@ -66,7 +67,7 @@ def __init__(self, xs, ys, zs, *args, **kwargs):
 
     def draw(self, renderer):
         xs3d, ys3d, zs3d = self._verts3d
-        x_s, y_s, _ = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M)
+        x_s, y_s, _ = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
         self.set_positions((x_s[0], y_s[0]), (x_s[1], y_s[1]))
         FancyArrowPatch.draw(self, renderer)
 
@@ -394,7 +395,17 @@ def render(self, title=""):
             self.fig = plt.figure(figsize=self.figsize)
 
         if not self._ext_axes:
-            self.axes = Axes3D(self.fig, azim=self.view[0], elev=self.view[1])
+            if tuple(int(x) for x in matplotlib.__version__.split(".")) >= (3, 4, 0):
+                self.axes = Axes3D(
+                    self.fig, azim=self.view[0], elev=self.view[1], auto_add_to_figure=False
+                )
+                self.fig.add_axes(self.axes)
+            else:
+                self.axes = Axes3D(
+                    self.fig,
+                    azim=self.view[0],
+                    elev=self.view[1],
+                )
 
         if self.background:
             self.axes.clear()
diff --git a/qiskit/visualization/transition_visualization.py b/qiskit/visualization/transition_visualization.py
--- a/qiskit/visualization/transition_visualization.py
+++ b/qiskit/visualization/transition_visualization.py
@@ -252,7 +252,12 @@ def visualize_transition(circuit, trace=False, saveas=None, fpg=100, spg=2):
     starting_pos = _normalize(np.array([0, 0, 1]))
 
     fig = plt.figure(figsize=(5, 5))
-    _ax = Axes3D(fig)
+    if tuple(int(x) for x in matplotlib.__version__.split(".")) >= (3, 4, 0):
+        _ax = Axes3D(fig, auto_add_to_figure=False)
+        fig.add_axes(_ax)
+    else:
+        _ax = Axes3D(fig)
+
     _ax.set_xlim(-10, 10)
     _ax.set_ylim(-10, 10)
     sphere = Bloch(axes=_ax)
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -79,7 +79,7 @@
 
 
 visualization_extras = [
-    "matplotlib>=2.1",
+    "matplotlib>=3.3",
     "ipywidgets>=7.3.0",
     "pydot",
     "pillow>=4.2.1",


Test patch:
diff --git a/test/python/visualization/references/20_plot_circuit_layout.png b/test/python/visualization/references/20_plot_circuit_layout.png
Binary files a/test/python/visualization/references/20_plot_circuit_layout.png and b/test/python/visualization/references/20_plot_circuit_layout.png differ
diff --git a/test/python/visualization/test_gate_map.py b/test/python/visualization/test_gate_map.py
--- a/test/python/visualization/test_gate_map.py
+++ b/test/python/visualization/test_gate_map.py
@@ -12,6 +12,7 @@
 
 """A test for visualizing device coupling maps"""
 import unittest
+import sys
 
 from io import BytesIO
 from PIL import Image
@@ -27,6 +28,12 @@
     import matplotlib.pyplot as plt
 
 
+@unittest.skipIf(
+    sys.version_info < (3, 7),
+    "Skipping image comparison tests on python 3.6 as they "
+    "depend on the local matplotlib environment matching the "
+    "environment for the reference images which is only >=3.7",
+)
 @ddt
 class TestGateMap(QiskitVisualizationTestCase):
     """visual tests for plot_gate_map"""