Repository: Qiskit/qiskit

Issue:
Exception in draw() when drawing appended circuits with both quantum and classical bits
<!-- ⚠️ 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.12.0
- **Python version**: 3.7.4
- **Operating system**: Windows 10

### What is the current behavior?

Let's take a look at two `QuantumCircuit` objects `qc1` and `qc2`, such that both of them have quantum and classical registers. If we append `qc2` to `qc1` and afterwards try to draw `qc1` in `output=text` mode, the following exception may occur 
```
d:\python_venvs\qiskit_venv\lib\site-packages\qiskit\visualization\text.py in _set_multibox(self, label, qubits, clbits, top_connect, bot_connect, conditional, controlled_edge)
   1051                 else:
   1052                     named_bit = self.qregs[bit_i]
-> 1053                     wire_label = ' ' * len(wire_label)
   1054                 self.set_qubit(named_bit, BoxOnQuWireMid(label, box_height, order,
   1055                                                          wire_label=wire_label))

UnboundLocalError: local variable 'wire_label' referenced before assignment
```

### Steps to reproduce the problem
Here is a sample code to reproduce
```
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit

qreg1 = QuantumRegister(2)
creg1 = ClassicalRegister(1)
qc1 = QuantumCircuit(qreg1, creg1)

qreg2 = QuantumRegister(1)
creg2 = ClassicalRegister(1)
qc2 = QuantumCircuit(qreg2, creg2)
qc2.measure(qreg2[0], creg2[0])

qc1.append(qc2, [qreg1[0]], [creg1[0]])
qc1.draw()
```
Important notes:
* `qc2` must have only one qubit in its quantum register
* `qc2` must be appended to `qc1` in such a way, that between `qc2`'s quantum and classical registers be at least one quantum register from `qc1` (in the above case it is the qubit `qreg1[1]`)

### What is the expected behavior?
Produce a drawing of the circuit.


### Suggested solutions
Either the line `wire_label = ' ' * len(wire_label)` should be changed, so that on the right hand side it does not rely on the value of `wire_label` from previous iteration of the for loop (and the `if` block), or the `wire_label` variable should be initialized before the loop. 



Discussion:
I have already examined the source code, and can fix this, and create a pull request.


Resolving patch:
diff --git a/qiskit/visualization/text.py b/qiskit/visualization/text.py
--- a/qiskit/visualization/text.py
+++ b/qiskit/visualization/text.py
@@ -1062,8 +1062,15 @@ def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None,
             clbits = list(clbits)
             cbit_index = sorted([i for i, x in enumerate(self.cregs) if x in clbits])
             qbit_index = sorted([i for i, x in enumerate(self.qregs) if x in qubits])
-            qargs = [str(qubits.index(qbit)) for qbit in self.qregs if qbit in qubits]
-            cargs = [str(clbits.index(cbit)) for cbit in self.cregs if cbit in clbits]
+
+            # Further below, indices are used as wire labels. Here, get the length of
+            # the longest label, and pad all labels with spaces to this length.
+            wire_label_len = max(len(str(len(qubits) - 1)),
+                                 len(str(len(clbits) - 1)))
+            qargs = [str(qubits.index(qbit)).ljust(wire_label_len, ' ')
+                     for qbit in self.qregs if qbit in qubits]
+            cargs = [str(clbits.index(cbit)).ljust(wire_label_len, ' ')
+                     for cbit in self.cregs if cbit in clbits]
 
             box_height = len(self.qregs) - min(qbit_index) + max(cbit_index) + 1
 
@@ -1075,7 +1082,7 @@ def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None,
                     wire_label = qargs.pop(0)
                 else:
                     named_bit = self.qregs[bit_i]
-                    wire_label = ' ' * len(wire_label)
+                    wire_label = ' ' * wire_label_len
                 self.set_qubit(named_bit, BoxOnQuWireMid(label, box_height, order,
                                                          wire_label=wire_label))
             for order, bit_i in enumerate(range(max(cbit_index)), order + 1):
@@ -1084,7 +1091,7 @@ def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None,
                     wire_label = cargs.pop(0)
                 else:
                     named_bit = self.cregs[bit_i]
-                    wire_label = ' ' * len(cargs[0])
+                    wire_label = ' ' * wire_label_len
                 self.set_clbit(named_bit, BoxOnClWireMid(label, box_height, order,
                                                          wire_label=wire_label))
             self.set_clbit(clbits.pop(0),
@@ -1093,6 +1100,7 @@ def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None,
         if qubits is None and clbits is not None:
             bits = list(clbits)
             bit_index = sorted([i for i, x in enumerate(self.cregs) if x in bits])
+            wire_label_len = len(str(len(bits) - 1))
             bits.sort(key=self.cregs.index)
             qargs = [''] * len(bits)
             set_bit = self.set_clbit
@@ -1103,7 +1111,9 @@ def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None,
         elif clbits is None and qubits is not None:
             bits = list(qubits)
             bit_index = sorted([i for i, x in enumerate(self.qregs) if x in bits])
-            qargs = [str(bits.index(qbit)) for qbit in self.qregs if qbit in bits]
+            wire_label_len = len(str(len(bits) - 1))
+            qargs = [str(bits.index(qbit)).ljust(wire_label_len, ' ')
+                     for qbit in self.qregs if qbit in bits]
             bits.sort(key=self.qregs.index)
             set_bit = self.set_qubit
             OnWire = BoxOnQuWire
@@ -1130,7 +1140,7 @@ def _set_multibox(self, label, qubits=None, clbits=None, top_connect=None,
                     wire_label = qargs.pop(0)
                 else:
                     named_bit = (self.qregs + self.cregs)[bit_i]
-                    wire_label = ' ' * len(qargs[0])
+                    wire_label = ' ' * wire_label_len
 
                 control_label = control_index.get(bit_i)
                 set_bit(named_bit, OnWireMid(label, box_height, order, wire_label=wire_label,


Test patch:
diff --git a/test/python/visualization/test_circuit_text_drawer.py b/test/python/visualization/test_circuit_text_drawer.py
--- a/test/python/visualization/test_circuit_text_drawer.py
+++ b/test/python/visualization/test_circuit_text_drawer.py
@@ -1688,6 +1688,99 @@ def test_text_4q_2c(self):
 
         self.assertEqual(str(_text_circuit_drawer(circuit)), expected)
 
+    def test_text_2q_1c(self):
+        """Test q0-c0 in q0-q1-c0
+        See https://github.com/Qiskit/qiskit-terra/issues/4066"""
+        expected = '\n'.join(["        ┌───────┐",
+                              "q_0: |0>┤0      ├",
+                              "        │       │",
+                              "q_1: |0>┤  Name ├",
+                              "        │       │",
+                              " c_0: 0 ╡0      ╞",
+                              "        └───────┘"])
+
+        qr = QuantumRegister(2, name='q')
+        cr = ClassicalRegister(1, name='c')
+        circuit = QuantumCircuit(qr, cr)
+        inst = QuantumCircuit(1, 1, name='Name').to_instruction()
+        circuit.append(inst, [qr[0]], [cr[0]])
+
+        self.assertEqual(str(_text_circuit_drawer(circuit)), expected)
+
+
+class TestTextDrawerAppendedLargeInstructions(QiskitTestCase):
+    """Composite instructions with more than 10 qubits
+    See https://github.com/Qiskit/qiskit-terra/pull/4095"""
+
+    def test_text_11q(self):
+        """Test q0-...-q10 in q0-...-q10"""
+        expected = '\n'.join(["         ┌────────┐",
+                              " q_0: |0>┤0       ├",
+                              "         │        │",
+                              " q_1: |0>┤1       ├",
+                              "         │        │",
+                              " q_2: |0>┤2       ├",
+                              "         │        │",
+                              " q_3: |0>┤3       ├",
+                              "         │        │",
+                              " q_4: |0>┤4       ├",
+                              "         │        │",
+                              " q_5: |0>┤5  Name ├",
+                              "         │        │",
+                              " q_6: |0>┤6       ├",
+                              "         │        │",
+                              " q_7: |0>┤7       ├",
+                              "         │        │",
+                              " q_8: |0>┤8       ├",
+                              "         │        │",
+                              " q_9: |0>┤9       ├",
+                              "         │        │",
+                              "q_10: |0>┤10      ├",
+                              "         └────────┘"])
+
+        qr = QuantumRegister(11, 'q')
+        circuit = QuantumCircuit(qr)
+        inst = QuantumCircuit(11, name='Name').to_instruction()
+        circuit.append(inst, qr)
+
+        self.assertEqual(str(_text_circuit_drawer(circuit)), expected)
+
+    def test_text_11q_1c(self):
+        """Test q0-...-q10-c0 in q0-...-q10-c0"""
+        expected = '\n'.join(["         ┌────────┐",
+                              " q_0: |0>┤0       ├",
+                              "         │        │",
+                              " q_1: |0>┤1       ├",
+                              "         │        │",
+                              " q_2: |0>┤2       ├",
+                              "         │        │",
+                              " q_3: |0>┤3       ├",
+                              "         │        │",
+                              " q_4: |0>┤4       ├",
+                              "         │        │",
+                              " q_5: |0>┤5       ├",
+                              "         │   Name │",
+                              " q_6: |0>┤6       ├",
+                              "         │        │",
+                              " q_7: |0>┤7       ├",
+                              "         │        │",
+                              " q_8: |0>┤8       ├",
+                              "         │        │",
+                              " q_9: |0>┤9       ├",
+                              "         │        │",
+                              "q_10: |0>┤10      ├",
+                              "         │        │",
+                              "  c_0: 0 ╡0       ╞",
+                              "         └────────┘"])
+
+        qr = QuantumRegister(11, 'q')
+        cr = ClassicalRegister(1, 'c')
+        circuit = QuantumCircuit(qr, cr)
+        inst = QuantumCircuit(11, 1, name='Name').to_instruction()
+        circuit.append(inst, qr, cr)
+
+        self.assertEqual(str(_text_circuit_drawer(circuit)), expected)
+
 
 class TestTextControlledGate(QiskitTestCase):
     """Test controlled gates"""