Example #1
0
def gen_channel_freqs(
        data: types.ChartAxis, formatter: Dict[str, Any],
        device: device_info.DrawerBackendInfo
) -> List[drawing_objects.TextData]:
    """Generate the frequency values of associated channels.

    Stylesheets:
        - The `axis_label` style is applied.
        - The `annotate` style is partially applied for the font size.

    Args:
        data: Chart axis data to draw.
        formatter: Dictionary of stylesheet settings.
        device: Backend configuration.

    Returns:
        List of `TextData` drawing objects.
    """
    style = {
        'zorder': formatter['layer.axis_label'],
        'color': formatter['color.axis_label'],
        'size': formatter['text_size.annotate'],
        'va': 'top',
        'ha': 'right'
    }

    if len(data.channels) > 1:
        sources = []
        for chan in data.channels:
            freq = device.get_channel_frequency(chan)
            if not freq:
                continue
            sources.append('{chan}: {val:.2f} GHz'.format(
                chan=chan.name.upper(), val=freq / 1e9))
        freq_text = ', '.join(sources)
    else:
        freq = device.get_channel_frequency(data.channels[0])
        if freq:
            freq_text = '{val:.2f} GHz'.format(val=freq / 1e9)
        else:
            freq_text = ''

    text = drawing_objects.TextData(
        data_type=types.DrawingLabel.CH_INFO,
        channels=data.channels,
        xvals=[types.AbstractCoordinate.LEFT],
        yvals=[formatter['label_offset.scale_factor']],
        text=freq_text or 'n/a',
        ignore_scaling=True,
        styles=style)

    return [text]
Example #2
0
def gen_channel_freqs(
        data: types.ChartAxis, formatter: Dict[str, Any],
        device: device_info.DrawerBackendInfo) -> List[drawings.TextData]:
    """Generate the frequency values of associated channels.

    Stylesheets:
        - The `axis_label` style is applied.
        - The `annotate` style is partially applied for the font size.

    Args:
        data: Chart axis data to draw.
        formatter: Dictionary of stylesheet settings.
        device: Backend configuration.

    Returns:
        List of `TextData` drawings.
    """
    style = {
        "zorder": formatter["layer.axis_label"],
        "color": formatter["color.axis_label"],
        "size": formatter["text_size.annotate"],
        "va": "center",
        "ha": "right",
    }

    if len(data.channels) > 1:
        sources = []
        for chan in data.channels:
            freq = device.get_channel_frequency(chan)
            if not freq:
                continue
            sources.append("{chan}: {val:.2f} GHz".format(
                chan=chan.name.upper(), val=freq / 1e9))
        freq_text = ", ".join(sources)
    else:
        freq = device.get_channel_frequency(data.channels[0])
        if freq:
            freq_text = "{val:.2f} GHz".format(val=freq / 1e9)
        else:
            freq_text = ""

    text = drawings.TextData(
        data_type=types.LabelType.CH_INFO,
        channels=data.channels,
        xvals=[types.AbstractCoordinate.LEFT],
        yvals=[-formatter["label_offset.chart_info"]],
        text=freq_text or "no freq.",
        ignore_scaling=True,
        styles=style,
    )

    return [text]
Example #3
0
def qubit_index_sort(
    channels: List[pulse.channels.Channel], formatter: Dict[str, Any],
    device: DrawerBackendInfo
) -> Iterator[Tuple[str, List[pulse.channels.Channel]]]:
    """Layout function for the channel assignment to the chart instance.

    Assign multiple channels per chart. Channels associated with the same qubit
    are grouped in the same chart and sorted by qubit index in ascending order.

    Acquire channels are not shown.

    Stylesheet key:
        `chart_channel_map`

    For example:
        [D0, D2, C0, C2, M0, M2, A0, A2] -> [Q0, Q1, Q2]

    Args:
        channels: Channels to show.
        formatter: Dictionary of stylesheet settings.
        device: Backend configuration.

    Yields:
        Tuple of chart name and associated channels.
    """
    _removed = (
        pulse.channels.AcquireChannel,
        pulse.channels.MemorySlot,
        pulse.channels.RegisterSlot,
    )

    qubit_channel_map = defaultdict(list)

    for chan in channels:
        if isinstance(chan, _removed):
            continue
        qubit_channel_map[device.get_qubit_index(chan)].append(chan)

    sorted_map = sorted(qubit_channel_map.items(), key=lambda x: x[0])

    for qind, chans in sorted_map:
        yield f"Q{qind:d}", chans
Example #4
0
def gen_filled_waveform_stepwise(
    data: types.PulseInstruction, formatter: Dict[str, Any],
    device: device_info.DrawerBackendInfo
) -> List[Union[drawings.LineData, drawings.BoxData, drawings.TextData]]:
    """Generate filled area objects of the real and the imaginary part of waveform envelope.

    The curve of envelope is not interpolated nor smoothed and presented
    as stepwise function at each data point.

    Stylesheets:
        - The `fill_waveform` style is applied.

    Args:
        data: Waveform instruction data to draw.
        formatter: Dictionary of stylesheet settings.
        device: Backend configuration.

    Returns:
        List of `LineData`, `BoxData`, or `TextData` drawings.

    Raises:
        VisualizationError: When the instruction parser returns invalid data format.
    """
    # generate waveform data
    waveform_data = _parse_waveform(data)
    channel = data.inst.channel

    # update metadata
    meta = waveform_data.meta
    qind = device.get_qubit_index(channel)
    meta.update({"qubit": qind if qind is not None else "N/A"})

    if isinstance(waveform_data, types.ParsedInstruction):
        # Draw waveform with fixed shape

        xdata = waveform_data.xvals
        ydata = waveform_data.yvals

        # phase modulation
        if formatter["control.apply_phase_modulation"]:
            ydata = np.asarray(ydata, dtype=complex) * np.exp(
                1j * data.frame.phase)
        else:
            ydata = np.asarray(ydata, dtype=complex)

        return _draw_shaped_waveform(xdata=xdata,
                                     ydata=ydata,
                                     meta=meta,
                                     channel=channel,
                                     formatter=formatter)

    elif isinstance(waveform_data, types.OpaqueShape):
        # Draw parametric pulse with unbound parameters

        # parameter name
        unbound_params = []
        for pname, pval in data.inst.pulse.parameters.items():
            if isinstance(pval, circuit.ParameterExpression):
                unbound_params.append(pname)

        if hasattr(data.inst.pulse, "pulse_type"):
            pulse_shape = data.inst.pulse.pulse_type
        else:
            pulse_shape = data.inst.pulse.__class__.__name__

        return _draw_opaque_waveform(
            init_time=data.t0,
            duration=waveform_data.duration,
            pulse_shape=pulse_shape,
            pnames=unbound_params,
            meta=meta,
            channel=channel,
            formatter=formatter,
        )

    else:
        raise VisualizationError("Invalid data format is provided.")
Example #5
0
def gen_filled_waveform_stepwise(data: types.PulseInstruction,
                                 formatter: Dict[str, Any],
                                 device: device_info.DrawerBackendInfo
                                 ) -> List[drawing_objects.LineData]:
    """Generate filled area objects of the real and the imaginary part of waveform envelope.

    The curve of envelope is not interpolated nor smoothed and presented
    as stepwise function at each data point.

    Stylesheets:
        - The `fill_waveform` style is applied.

    Args:
        data: Waveform instruction data to draw.
        formatter: Dictionary of stylesheet settings.
        device: Backend configuration.

    Returns:
        List of `LineData` drawing objects.
    """
    fill_objs = []

    # generate waveform data
    parsed = _parse_waveform(data)
    channel = data.inst.channel
    qubit = device.get_qubit_index(channel)
    if qubit is None:
        qubit = 'N/A'
    resolution = formatter['general.vertical_resolution']

    # phase modulation
    if formatter['control.apply_phase_modulation']:
        ydata = np.asarray(parsed.yvals, dtype=np.complex) * np.exp(1j * data.frame.phase)
    else:
        ydata = np.asarray(parsed.yvals, dtype=np.complex)

    # stepwise interpolation
    xdata = np.concatenate((parsed.xvals, [parsed.xvals[-1] + 1]))
    ydata = np.repeat(ydata, 2)
    re_y = np.real(ydata)
    im_y = np.imag(ydata)
    time = np.concatenate(([xdata[0]], np.repeat(xdata[1:-1], 2), [xdata[-1]]))

    # setup style options
    style = {'alpha': formatter['alpha.fill_waveform'],
             'zorder': formatter['layer.fill_waveform'],
             'linewidth': formatter['line_width.fill_waveform'],
             'linestyle': formatter['line_style.fill_waveform']}

    color_code = types.ComplexColors(*formatter[_fill_waveform_color(channel)])

    # create real part
    if np.any(re_y):
        # data compression
        re_valid_inds = _find_consecutive_index(re_y, resolution)
        # stylesheet
        re_style = {'color': color_code.real}
        re_style.update(style)
        # metadata
        re_meta = {'data': 'real', 'qubit': qubit}
        re_meta.update(parsed.meta)
        # active xy data
        re_xvals = time[re_valid_inds]
        re_yvals = re_y[re_valid_inds]

        # object
        real = drawing_objects.LineData(data_type=types.DrawingWaveform.REAL,
                                        channels=channel,
                                        xvals=re_xvals,
                                        yvals=re_yvals,
                                        fill=True,
                                        meta=re_meta,
                                        styles=re_style)
        fill_objs.append(real)

    # create imaginary part
    if np.any(im_y):
        # data compression
        im_valid_inds = _find_consecutive_index(im_y, resolution)
        # stylesheet
        im_style = {'color': color_code.imaginary}
        im_style.update(style)
        # metadata
        im_meta = {'data': 'imag', 'qubit': qubit}
        im_meta.update(parsed.meta)
        # active xy data
        im_xvals = time[im_valid_inds]
        im_yvals = im_y[im_valid_inds]

        # object
        imag = drawing_objects.LineData(data_type=types.DrawingWaveform.IMAG,
                                        channels=channel,
                                        xvals=im_xvals,
                                        yvals=im_yvals,
                                        fill=True,
                                        meta=im_meta,
                                        styles=im_style)
        fill_objs.append(imag)

    return fill_objs