Repository: Qiskit/qiskit

Issue:
Backend monitor displays incorrect information
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- master
- any
- any

### What is the current behavior?
Qubit anharmonicities, in GHz, appear in the Readout Properties column of the Backend Monitor generated by the code in https://github.com/Qiskit/qiskit-terra/blob/master/qiskit/tools/jupyter/backend_monitor.py. This is true at least for backends that are currently reporting anharmonicities, which may not be all of them yet, but will be soon.

### Steps to reproduce the problem
In a Jupyter notebook, type `provider.get_backend('ibmq_montreal')`
Observe issue as below:
![image](https://user-images.githubusercontent.com/27903437/91843733-3aefe700-ec24-11ea-8bc3-7abf478b16a2.png)


### What is the expected behavior?
Readout properties column should show readout properties


### Suggested solutions
-Fix the code near line 282 of the mentioned file to not hard-code the array indices of different qubit properties in the qubit_data array.
-Consider adding a column for anharmonicity to the table (or not).




Discussion:
@dtmcclure  Can I try this?
@Arijit02 all yours. Feel free to reach out with any questions.
Yes, sure. I would love to.

Resolving patch:
diff --git a/qiskit/tools/jupyter/backend_monitor.py b/qiskit/tools/jupyter/backend_monitor.py
--- a/qiskit/tools/jupyter/backend_monitor.py
+++ b/qiskit/tools/jupyter/backend_monitor.py
@@ -245,11 +245,13 @@ def qubits_tab(backend):
     Returns:
         VBox: A VBox widget.
     """
-    props = backend.properties().to_dict()
+    props = backend.properties()
 
     header_html = "<div><font style='font-weight:bold'>{key}</font>: {value}</div>"
+    update_date = props.last_update_date.strftime("%a %d %B %Y at %H:%M %Z")
     header_html = header_html.format(key='last_update_date',
-                                     value=props['last_update_date'])
+                                     value=update_date)
+
     update_date_widget = widgets.HTML(value=header_html)
 
     qubit_html = "<table>"
@@ -268,43 +270,42 @@ def qubits_tab(backend):
 </style>"""
 
     qubit_html += "<tr><th></th><th>Frequency</th><th>T1</th><th>T2</th>"
-    qubit_html += "<th>U1 gate error</th><th>U2 gate error</th><th>U3 gate error</th>"
-    qubit_html += "<th>Readout error</th></tr>"
     qubit_footer = "</table>"
 
-    for qub in range(len(props['qubits'])):
-        name = 'Q%s' % qub
-        qubit_data = props['qubits'][qub]
-        gate_data = [g for g in props['gates'] if g['qubits'] == [qub]]
-        t1_info = qubit_data[0]
-        t2_info = qubit_data[1]
-        freq_info = qubit_data[2]
-        readout_info = qubit_data[3]
-
-        freq = str(round(freq_info['value'], 5))+' '+freq_info['unit']
-        T1 = str(round(t1_info['value'],
-                       5))+' ' + t1_info['unit']
-        T2 = str(round(t2_info['value'],
-                       5))+' ' + t2_info['unit']
+    gate_error_title = ""
 
-        for gd in gate_data:
-            if gd['gate'] == 'u1':
-                U1 = str(round(gd['parameters'][0]['value'], 5))
-                break
+    for index, qubit_data in enumerate(props.qubits):
+        name = 'Q%s' % index
+        gate_data = [gate for gate in props.gates if gate.qubits == [index]]
 
+        cal_data = dict.fromkeys(['T1', 'T2', 'frequency', 'readout_error'], 'Unknown')
+        for nduv in qubit_data:
+            if nduv.name in cal_data.keys():
+                cal_data[nduv.name] = str(round(nduv.value, 5)) + ' ' + nduv.unit
+
+        gate_names = []
+        gate_error = []
         for gd in gate_data:
-            if gd['gate'] == 'u2':
-                U2 = str(round(gd['parameters'][0]['value'], 5))
-                break
-        for gd in gate_data:
-            if gd['gate'] == 'u3':
-                U3 = str(round(gd['parameters'][0]['value'], 5))
-                break
-
-        readout_error = round(readout_info['value'], 5)
-        qubit_html += "<tr><td><font style='font-weight:bold'>%s</font></td><td>%s</td>"
-        qubit_html += "<td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>"
-        qubit_html = qubit_html % (name, freq, T1, T2, U1, U2, U3, readout_error)
+            if gd.gate in ['id']:
+                continue
+            try:
+                gate_error.append(str(round(props.gate_error(gd.gate, index), 5)))
+                gate_names.append(gd.gate.upper())
+            except QiskitError:
+                pass
+
+        if not gate_error_title:
+            for gname in gate_names:
+                gate_error_title += f"<th>{gname}</th>"
+            qubit_html += gate_error_title + "<th>Readout error</th></tr>"
+
+        qubit_html += f"<tr><td><font style='font-weight:bold'>{name}</font></td>"
+        qubit_html += f"<td>{cal_data['frequency']}</td>" \
+                      f"<td>{cal_data['T1']}</td><td>{cal_data['T2']}</td>"
+        for gerror in gate_error:
+            qubit_html += f"<td>{gerror}</td>"
+        qubit_html += f"<td>{cal_data['readout_error']}</td>"
+
     qubit_html += qubit_footer
 
     qubit_widget = widgets.HTML(value=qubit_html)
@@ -324,13 +325,13 @@ def gates_tab(backend):
     Returns:
         VBox: A VBox widget.
     """
-    props = backend.properties().to_dict()
+    props = backend.properties()
 
-    multi_qubit_gates = [g for g in props['gates'] if len(g['qubits']) > 1]
+    multi_qubit_gates = [g for g in props.gates if len(g.qubits) > 1]
 
     header_html = "<div><font style='font-weight:bold'>{key}</font>: {value}</div>"
     header_html = header_html.format(key='last_update_date',
-                                     value=props['last_update_date'])
+                                     value=props.last_update_date)
 
     update_date_widget = widgets.HTML(value=header_html,
                                       layout=widgets.Layout(grid_area='top'))
@@ -361,9 +362,9 @@ def gates_tab(backend):
 
     for qub in range(left_num):
         gate = multi_qubit_gates[qub]
-        qubits = gate['qubits']
-        ttype = gate['gate']
-        error = round(gate['parameters'][0]['value'], 5)
+        qubits = gate.qubits
+        ttype = gate.gate
+        error = round(props.gate_error(gate.gate, qubits), 5)
 
         left_table += "<tr><td><font style='font-weight:bold'>%s</font>"
         left_table += "</td><td>%s</td><td>%s</td></tr>"
@@ -375,9 +376,9 @@ def gates_tab(backend):
 
     for qub in range(left_num, left_num+mid_num):
         gate = multi_qubit_gates[qub]
-        qubits = gate['qubits']
-        ttype = gate['gate']
-        error = round(gate['parameters'][0]['value'], 5)
+        qubits = gate.qubits
+        ttype = gate.gate
+        error = round(props.gate_error(gate.gate, qubits), 5)
 
         middle_table += "<tr><td><font style='font-weight:bold'>%s</font>"
         middle_table += "</td><td>%s</td><td>%s</td></tr>"
@@ -389,9 +390,9 @@ def gates_tab(backend):
 
     for qub in range(left_num+mid_num, len(multi_qubit_gates)):
         gate = multi_qubit_gates[qub]
-        qubits = gate['qubits']
-        ttype = gate['gate']
-        error = round(gate['parameters'][0]['value'], 5)
+        qubits = gate.qubits
+        ttype = gate.gate
+        error = round(props.gate_error(gate.gate, qubits), 5)
 
         right_table += "<tr><td><font style='font-weight:bold'>%s</font>"
         right_table += "</td><td>%s</td><td>%s</td></tr>"
diff --git a/qiskit/tools/monitor/overview.py b/qiskit/tools/monitor/overview.py
--- a/qiskit/tools/monitor/overview.py
+++ b/qiskit/tools/monitor/overview.py
@@ -71,8 +71,6 @@ def backend_monitor(backend):
     config = backend.configuration().to_dict()
     status = backend.status().to_dict()
     config_dict = {**status, **config}
-    if not config['simulator']:
-        props = backend.properties().to_dict()
 
     print(backend.name())
     print('='*len(backend.name()))
@@ -96,55 +94,56 @@ def backend_monitor(backend):
         return
 
     print()
-    qubit_header = 'Qubits [Name / Freq / T1 / T2 / U1 err / U2 err / U3 err / Readout err]'
-    print(qubit_header)
-    print('-'*len(qubit_header))
-
+    props = backend.properties()
+    qubit_header = None
     sep = ' / '
-    for qub in range(len(props['qubits'])):
-        name = 'Q%s' % qub
-        qubit_data = props['qubits'][qub]
-        gate_data = [g for g in props['gates'] if g['qubits'] == [qub]]
-        t1_info = qubit_data[0]
-        t2_info = qubit_data[1]
-        freq_info = qubit_data[2]
-        readout_info = qubit_data[3]
-
-        freq = str(round(freq_info['value'], 5))+' '+freq_info['unit']
-        T1 = str(round(t1_info['value'],
-                       5))+' ' + t1_info['unit']
-        T2 = str(round(t2_info['value'],
-                       5))+' ' + t2_info['unit']
-        for gd in gate_data:
-            if gd['gate'] == 'u1':
-                U1 = str(round(gd['parameters'][0]['value'], 5))
-                break
 
-        for gd in gate_data:
-            if gd['gate'] == 'u2':
-                U2 = str(round(gd['parameters'][0]['value'], 5))
-                break
-        for gd in gate_data:
-            if gd['gate'] == 'u3':
-                U3 = str(round(gd['parameters'][0]['value'], 5))
-                break
+    for index, qubit_data in enumerate(props.qubits):
+        name = 'Q%s' % index
+        gate_data = [gate for gate in props.gates if gate.qubits == [index]]
 
-        readout_error = str(round(readout_info['value'], 5))
+        cal_data = dict.fromkeys(['T1', 'T2', 'frequency', 'readout_error'], 'Unknown')
+        for nduv in qubit_data:
+            if nduv.name in cal_data.keys():
+                cal_data[nduv.name] = format(nduv.value, '.5f') + ' ' + nduv.unit
+
+        gate_names = []
+        gate_error = []
+        for gd in gate_data:
+            if gd.gate in ['id']:
+                continue
+            try:
+                gate_error.append(format(props.gate_error(gd.gate, index), '.5f'))
+                gate_names.append(gd.gate.upper() + ' err')
+            except QiskitError:
+                pass
+
+        if not qubit_header:
+            qubit_header = 'Qubits [Name / Freq / T1 / T2' + sep.join(['']+gate_names) + \
+                           ' / Readout err]'
+            print(qubit_header)
+            print('-'*len(qubit_header))
+
+        qstr = sep.join([name, cal_data['frequency'], cal_data['T1'], cal_data['T2']] +
+                        gate_error +
+                        [cal_data['readout_error']])
 
-        qstr = sep.join([name, freq, T1, T2, U1, U2, U3, readout_error])
         print(offset+qstr)
 
     print()
-    multi_qubit_gates = [g for g in props['gates'] if len(g['qubits']) > 1]
+    multi_qubit_gates = [g for g in props.gates if len(g.qubits) > 1]
     multi_header = 'Multi-Qubit Gates [Name / Type / Gate Error]'
     print(multi_header)
     print('-'*len(multi_header))
 
-    for qub, gate in enumerate(multi_qubit_gates):
-        gate = multi_qubit_gates[qub]
-        qubits = gate['qubits']
-        ttype = gate['gate']
-        error = round(gate['parameters'][0]['value'], 5)
+    for gate in multi_qubit_gates:
+        qubits = gate.qubits
+        ttype = gate.gate
+        error = "Unknown"
+        try:
+            error = format(props.gate_error(gate.gate, qubits), '.5f')
+        except QiskitError:
+            pass
         mstr = sep.join(["{}{}_{}".format(ttype, qubits[0], qubits[1]), ttype, str(error)])
         print(offset+mstr)
 


Test patch:
diff --git a/test/python/providers/test_backendproperties.py b/test/python/providers/test_backendproperties.py
--- a/test/python/providers/test_backendproperties.py
+++ b/test/python/providers/test_backendproperties.py
@@ -31,6 +31,8 @@ def setUp(self):
         self.provider = FakeProvider()
         self.backend = self.provider.get_backend('fake_ourense')
         self.properties = self.backend.properties()
+        self.ref_gate = next(g for g in self.backend.configuration().basis_gates
+                             if g not in ['id', 'rz'])
 
     def test_gate_property(self):
         """Test for getting the gate properties."""
@@ -40,14 +42,14 @@ def test_gate_property(self):
                          self.properties._gates['cx'])
 
         with self.assertRaises(BackendPropertyError):
-            self.properties.gate_property('u1', None, 'gate_error')
+            self.properties.gate_property(self.ref_gate, None, 'gate_error')
 
     def test_gate_error(self):
         """Test for getting the gate errors."""
-        self.assertEqual(self.properties.gate_error('u1', 1),
-                         self.properties._gates['u1'][(1,)]['gate_error'][0])
-        self.assertEqual(self.properties.gate_error('u1', [2, ]),
-                         self.properties._gates['u1'][(2,)]['gate_error'][0])
+        self.assertEqual(self.properties.gate_error(self.ref_gate, 1),
+                         self.properties._gates[self.ref_gate][(1,)]['gate_error'][0])
+        self.assertEqual(self.properties.gate_error(self.ref_gate, [2, ]),
+                         self.properties._gates[self.ref_gate][(2,)]['gate_error'][0])
         self.assertEqual(self.properties.gate_error('cx', [0, 1]),
                          self.properties._gates['cx'][(0, 1)]['gate_error'][0])
 
@@ -56,8 +58,8 @@ def test_gate_error(self):
 
     def test_gate_length(self):
         """Test for getting the gate duration."""
-        self.assertEqual(self.properties.gate_length('u1', 1),
-                         self.properties._gates['u1'][(1,)]['gate_length'][0])
+        self.assertEqual(self.properties.gate_length(self.ref_gate, 1),
+                         self.properties._gates[self.ref_gate][(1,)]['gate_length'][0])
         self.assertEqual(self.properties.gate_length('cx', [4, 3]),
                          self.properties._gates['cx'][(4, 3)]['gate_length'][0])
 
diff --git a/test/python/tools/monitor/test_backend_monitor.py b/test/python/tools/monitor/test_backend_monitor.py
--- a/test/python/tools/monitor/test_backend_monitor.py
+++ b/test/python/tools/monitor/test_backend_monitor.py
@@ -95,8 +95,11 @@ def test_backend_monitor(self, _):
 
         stdout = fake_stdout.getvalue()
         self.assertIn('Configuration', stdout)
-        self.assertIn('Qubits [Name / Freq / T1 / T2 / U1 err / U2 err / U3 err / Readout err]',
-                      stdout)
+        self.assertIn('Qubits [Name / Freq / T1 / T2 / ', stdout)
+        for gate in backend.properties().gates:
+            if gate.gate not in ['id'] and len(gate.qubits) == 1:
+                self.assertIn(gate.gate.upper() + ' err', stdout)
+        self.assertIn('Readout err', stdout)
         self.assertIn('Multi-Qubit Gates [Name / Type / Gate Error]', stdout)
 
 
diff --git a/test/python/transpiler/test_instruction_durations.py b/test/python/transpiler/test_instruction_durations.py
--- a/test/python/transpiler/test_instruction_durations.py
+++ b/test/python/transpiler/test_instruction_durations.py
@@ -36,13 +36,28 @@ def test_fail_if_invalid_dict_is_supplied_when_construction(self):
             InstructionDurations(invalid_dic)
 
     def test_from_backend_for_backend_with_dt(self):
-        durations = InstructionDurations.from_backend(FakeParis())
+        backend = FakeParis()
+        gate = self._find_gate_length_gate(backend)
+        durations = InstructionDurations.from_backend(backend)
         self.assertGreater(durations.dt, 0)
-        self.assertGreater(durations.get('u2', 0), 0)
+        self.assertGreater(durations.get(gate, 0), 0)
 
     def test_from_backend_for_backend_without_dt(self):
-        durations = InstructionDurations.from_backend(FakeTokyo())
+        backend = FakeTokyo()
+        gate = self._find_gate_length_gate(backend)
+        durations = InstructionDurations.from_backend(backend)
         self.assertIsNone(durations.dt)
-        self.assertGreater(durations.get('u2', 0, 's'), 0)
+        self.assertGreater(durations.get(gate, 0, 's'), 0)
         with self.assertRaises(TranspilerError):
-            durations.get('u2', 0)
+            durations.get(gate, 0)
+
+    def _find_gate_length_gate(self, backend):
+        """Find a gate that has gate length."""
+        props = backend.properties()
+        for gate in props.gates:
+            try:
+                if props.gate_length(gate.gate, 0):
+                    return gate.gate
+            except Exception:  # pylint: disable=broad-except
+                pass
+        raise ValueError("Unable to find a gate with gate length.")