• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Qiskit / qiskit / 9501038851

13 Jun 2024 01:59PM CUT coverage: 89.756% (+0.003%) from 89.753%
9501038851

Pull #12568

github

web-flow
Merge 59bbcaa89 into 2d6a5a2bb
Pull Request #12568: Bump pypa/cibuildwheel from 2.17.0 to 2.19.1 in the github_actions group across 1 directory

63419 of 70657 relevant lines covered (89.76%)

302742.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/qiskit/visualization/pulse_v2/plotters/matplotlib.py
1
# This code is part of Qiskit.
2
#
3
# (C) Copyright IBM 2020.
4
#
5
# This code is licensed under the Apache License, Version 2.0. You may
6
# obtain a copy of this license in the LICENSE.txt file in the root directory
7
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8
#
9
# Any modifications or derivative works of this code must retain this
10
# copyright notice, and modified files need to carry a notice indicating
11
# that they have been altered from the originals.
12

13
"""Matplotlib plotter API."""
14

15
from typing import Optional
×
16

17
import matplotlib
×
18
import matplotlib.pyplot as plt
×
19
import numpy as np
×
20
from matplotlib.patches import Rectangle
×
21

22
from qiskit.visualization.exceptions import VisualizationError
×
23
from qiskit.visualization.pulse_v2 import core, drawings, types
×
24
from qiskit.visualization.pulse_v2.plotters.base_plotter import BasePlotter
×
25
from qiskit.visualization.utils import matplotlib_close_if_inline
×
26

27

28
class Mpl2DPlotter(BasePlotter):
×
29
    """Matplotlib API for pulse drawer.
30

31
    This plotter places canvas charts along y axis of 2D canvas with vertical offset.
32
    Each chart is map to X-Y axis of the canvas.
33
    """
34

35
    def __init__(self, canvas: core.DrawerCanvas, axis: Optional[plt.Axes] = None):
×
36
        """Create new plotter.
37

38
        Args:
39
            canvas: Configured drawer canvas object. Canvas object should be updated
40
                with `.update` method before set to the plotter API.
41
            axis: Matplotlib axis object. When `axis` is provided, the plotter updates
42
                given axis instead of creating and returning new matplotlib figure.
43
        """
44
        super().__init__(canvas=canvas)
×
45

46
        # calculate height of all charts
47
        canvas_height = 0
×
48
        for chart in self.canvas.charts:
×
49
            if not chart.is_active and not self.canvas.formatter["control.show_empty_channel"]:
×
50
                continue
×
51
            canvas_height += chart.vmax - chart.vmin
×
52
        # set min canvas_height size
53
        canvas_height = max(canvas_height, 0.1)
×
54

55
        if axis is None:
×
56
            fig_h = canvas_height * self.canvas.formatter["general.fig_chart_height"]
×
57
            fig_w = self.canvas.formatter["general.fig_width"]
×
58

59
            self.figure = plt.figure(figsize=(fig_w, fig_h))
×
60
            self.ax = self.figure.add_subplot(1, 1, 1)
×
61
        else:
62
            self.figure = axis.figure
×
63
            self.ax = axis
×
64

65
        self.initialize_canvas()
×
66

67
    def initialize_canvas(self):
×
68
        """Format appearance of matplotlib canvas."""
69
        self.ax.set_facecolor(self.canvas.formatter["color.background"])
×
70

71
        # axis labels
72
        self.ax.set_yticklabels([])
×
73
        self.ax.yaxis.set_tick_params(left=False)
×
74

75
    def draw(self):
×
76
        """Output drawings stored in canvas object."""
77
        # axis configuration
78
        axis_config = self.canvas.layout["time_axis_map"](
×
79
            time_window=self.canvas.time_range,
80
            axis_breaks=self.canvas.time_breaks,
81
            dt=self.canvas.device.dt,
82
        )
83

84
        current_y = 0
×
85
        margin_y = self.canvas.formatter["margin.between_channel"]
×
86
        for chart in self.canvas.charts:
×
87
            if not chart.is_active and not self.canvas.formatter["control.show_empty_channel"]:
×
88
                continue
×
89
            current_y -= chart.vmax
×
90
            for _, data in chart.collections:
×
91
                # calculate scaling factor
92
                if not data.ignore_scaling:
×
93
                    # product of channel-wise scaling and chart level scaling
94
                    scale = max(self.canvas.chan_scales.get(chan, 1.0) for chan in data.channels)
×
95
                    scale *= chart.scale
×
96
                else:
97
                    scale = 1.0
×
98

99
                x = data.xvals
×
100
                y = scale * data.yvals + current_y
×
101

102
                if isinstance(data, drawings.LineData):
×
103
                    # line object
104
                    if data.fill:
×
105
                        self.ax.fill_between(x, y1=y, y2=current_y * np.ones_like(y), **data.styles)
×
106
                    else:
107
                        self.ax.plot(x, y, **data.styles)
×
108
                elif isinstance(data, drawings.TextData):
×
109
                    # text object
110
                    text = rf"${data.latex}$" if data.latex else data.text
×
111
                    # replace dynamic text
112
                    text = text.replace(types.DynamicString.SCALE, f"{chart.scale:.1f}")
×
113
                    self.ax.text(x=x[0], y=y[0], s=text, **data.styles)
×
114
                elif isinstance(data, drawings.BoxData):
×
115
                    xy = x[0], y[0]
×
116
                    box = Rectangle(
×
117
                        xy, width=x[1] - x[0], height=y[1] - y[0], fill=True, **data.styles
118
                    )
119
                    self.ax.add_patch(box)
×
120
                else:
121
                    raise VisualizationError(
×
122
                        "Data {name} is not supported "
123
                        "by {plotter}".format(name=data, plotter=self.__class__.__name__)
124
                    )
125
            # axis break
126
            for pos in axis_config.axis_break_pos:
×
127
                self.ax.text(
×
128
                    x=pos,
129
                    y=current_y,
130
                    s="//",
131
                    ha="center",
132
                    va="center",
133
                    zorder=self.canvas.formatter["layer.axis_label"],
134
                    fontsize=self.canvas.formatter["text_size.axis_break_symbol"],
135
                    rotation=180,
136
                )
137

138
            # shift chart position
139
            current_y += chart.vmin - margin_y
×
140

141
        # remove the last margin
142
        current_y += margin_y
×
143

144
        y_max = self.canvas.formatter["margin.top"]
×
145
        y_min = current_y - self.canvas.formatter["margin.bottom"]
×
146

147
        # plot axis break line
148
        for pos in axis_config.axis_break_pos:
×
149
            self.ax.plot(
×
150
                [pos, pos],
151
                [y_min, y_max],
152
                zorder=self.canvas.formatter["layer.fill_waveform"] + 1,
153
                linewidth=self.canvas.formatter["line_width.axis_break"],
154
                color=self.canvas.formatter["color.background"],
155
            )
156

157
        # label
158
        self.ax.set_xticks(list(axis_config.axis_map.keys()))
×
159
        self.ax.set_xticklabels(
×
160
            list(axis_config.axis_map.values()),
161
            fontsize=self.canvas.formatter["text_size.axis_label"],
162
        )
163
        self.ax.set_xlabel(
×
164
            axis_config.label, fontsize=self.canvas.formatter["text_size.axis_label"]
165
        )
166

167
        # boundary
168
        if axis_config.window == (0, 0):
×
169
            self.ax.set_xlim(0, 1)
×
170
        else:
171
            self.ax.set_xlim(*axis_config.window)
×
172
        self.ax.set_ylim(y_min, y_max)
×
173

174
        # title
175
        if self.canvas.fig_title:
×
176
            self.ax.text(
×
177
                x=axis_config.window[0],
178
                y=y_max,
179
                s=self.canvas.fig_title,
180
                ha="left",
181
                va="bottom",
182
                zorder=self.canvas.formatter["layer.fig_title"],
183
                color=self.canvas.formatter["color.fig_title"],
184
                size=self.canvas.formatter["text_size.fig_title"],
185
            )
186

187
    def get_image(self, interactive: bool = False) -> matplotlib.pyplot.Figure:
×
188
        """Get image data to return.
189

190
        Args:
191
            interactive: When set `True` show the circuit in a new window.
192
                This depends on the matplotlib backend being used supporting this.
193

194
        Returns:
195
            Matplotlib figure data.
196
        """
197
        matplotlib_close_if_inline(self.figure)
×
198

199
        if self.figure and interactive:
×
200
            self.figure.show()
×
201

202
        return self.figure
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc