Repository: Qiskit/qiskit

Issue:
Plotting of instruction schedule from mock backend fails
<!-- ⚠️ 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.17.0.dev0+6f0eca6'
- **Python version**: 3.8.6
- **Operating system**: Windows 10

The output of `qiskit.version.QiskitVersion()` is
```
{'qiskit-terra': '0.17.0.dev0+6f0eca6', 'qiskit-aer': '0.7.3', 'qiskit-ignis': '0.5.1', 'qiskit-ibmq-provider': '0.11.1', 'qiskit-aqua': '0.8.1', 'qiskit': '0.23.4'}
```

### What is the current behavior?

When importing the `FakeAthens`, gettting the schedule for the `u3` instruction and plotting an exception is generated.

Depending on this qiskit version I get different error messages. The version reported above yields:
```
...
  File "c:\projects\qiskit-terra\qiskit\visualization\pulse_v2\generators\frame.py", line 318, in gen_frame_symbol
    program.append('{}({})'.format(inst.__class__.__name__, inst.phase.name))

AttributeError: 'ParameterExpression' object has no attribute 'name'
```

### Steps to reproduce the problem

A minimal example is:
```
from qiskit.test.mock import FakeAthens

backend = FakeAthens()
defaults = backend.defaults()
inst_map = defaults.instruction_schedule_map
schedule=inst_map.get('u3', [0])
schedule.draw()
```
print(qiskit.version.QiskitVersion())

### What is the expected behavior?

The schedule should be plotted


### Suggested solutions

None




Discussion:
@nkanazawa1989 I believe this was a bug introduced with the release of parameters + schedules. Would you mind having a look?
@taalexander @nkanazawa1989 The issues still exists on current master.
```
In [5]: print(qiskit.version.QiskitVersion())
{'qiskit-terra': '0.18.0.dev0+98130dd', 'qiskit-aer': '0.8.0', 'qiskit-ignis': '0.6.0', 'qiskit-ibmq-provider': '0.12.2', 'qiskit-aqua': '0.9.0', 'qiskit': '0.25.0', 'qiskit-nature': None, 'qiskit-finance': None, 'qiskit-optimization': None, 'qiskit-machine-learning': None}
```
Investigating this a result of the implementation of `partial` which does not fully bind your argument but rather creates a new function with the partially bound argument as a keyword argument. 

```python
import inspect

inspect.signature(partial(callable_schedule2, amplitude=.4))
```
```
>>> <Signature (f, *, amplitude=0.4)>
```

See [partial docs](https://docs.python.org/3/library/functools.html#functools.partial) for a description of how it works. In general I would expect any function with keyword arguments to have this issue as these keyword arguments would be treated as arguments for the instruction calibration, we do not support optional arguments in mapping circuit instructions to schedules as circuit instructions do not support optional arguments themselves.

Its a question of what the expected behaviour should be? The two options are:
1. Keyword arguments are mandatory arguments for the schedule generation method from the `InstructionScheduleMap`'s perspective.
2. Keyword arguments are ignored from the instruction schedule maps perspective.

Resolving patch:
diff --git a/qiskit/visualization/pulse_v2/generators/frame.py b/qiskit/visualization/pulse_v2/generators/frame.py
--- a/qiskit/visualization/pulse_v2/generators/frame.py
+++ b/qiskit/visualization/pulse_v2/generators/frame.py
@@ -309,13 +309,13 @@ def gen_frame_symbol(data: types.PulseInstruction,
                 program.append('{}({:.2e} Hz)'.format(inst.__class__.__name__, inst.frequency))
             except TypeError:
                 # parameter expression
-                program.append('{}({})'.format(inst.__class__.__name__, inst.frequency.name))
+                program.append('{}({})'.format(inst.__class__.__name__, inst.frequency))
         elif isinstance(inst, (instructions.SetPhase, instructions.ShiftPhase)):
             try:
                 program.append('{}({:.2f} rad.)'.format(inst.__class__.__name__, inst.phase))
             except TypeError:
                 # parameter expression
-                program.append('{}({})'.format(inst.__class__.__name__, inst.phase.name))
+                program.append('{}({})'.format(inst.__class__.__name__, inst.phase))
 
     meta = {'total phase change': data.frame.phase,
             'total frequency change': data.frame.freq,
diff --git a/qiskit/visualization/pulse_v2/generators/waveform.py b/qiskit/visualization/pulse_v2/generators/waveform.py
--- a/qiskit/visualization/pulse_v2/generators/waveform.py
+++ b/qiskit/visualization/pulse_v2/generators/waveform.py
@@ -170,9 +170,6 @@ def gen_ibmq_latex_waveform_name(data: types.PulseInstruction,
     elif isinstance(data.inst, instructions.Delay):
         systematic_name = data.inst.name or 'Delay'
         latex_name = None
-    elif isinstance(data.inst.channel, pulse.channels.MeasureChannel):
-        systematic_name = 'Measure'
-        latex_name = None
     else:
         systematic_name = data.inst.pulse.name or data.inst.pulse.__class__.__name__
 


Test patch:
diff --git a/test/python/visualization/pulse_v2/test_generators.py b/test/python/visualization/pulse_v2/test_generators.py
--- a/test/python/visualization/pulse_v2/test_generators.py
+++ b/test/python/visualization/pulse_v2/test_generators.py
@@ -669,6 +669,26 @@ def gen_frame_symbol(self):
                      'ha': 'center'}
         self.assertDictEqual(obj.styles, ref_style)
 
+    def gen_frame_symbol_with_parameters(self):
+        """Test gen_frame_symbol with parameterized frame."""
+        theta = -1.0 * circuit.Parameter('P0')
+        fcs = [pulse.ShiftPhase(theta, pulse.DriveChannel(0))]
+        inst_data = create_instruction(fcs, np.pi / 2, 1e6, 5, 0.1)
+
+        obj = frame.gen_frame_symbol(inst_data,
+                                     formatter=self.formatter,
+                                     device=self.device)[0]
+
+        # metadata check
+        ref_meta = {
+            'total phase change': np.pi/2,
+            'total frequency change': 1e6,
+            'program': ['ShiftPhase(-1.0*P0)'],
+            't0 (cycle time)': 5,
+            't0 (sec)': 0.5
+        }
+        self.assertDictEqual(obj.meta, ref_meta)
+
 
 class TestSnapshotGenerators(QiskitTestCase):
     """Tests for snapshot generators."""