Example #1
0
def test_data_MC(
    mock_asimov,
    mock_unc,
    mock_stdev,
    mock_table_bin,
    mock_table_channel,
    mock_dict,
    mock_bins,
    mock_draw,
    example_spec,
):
    config = {"config": "abc"}
    figure_folder = "tmp"
    model, data = model_utils.model_and_data(example_spec)

    # pre-fit plot
    visualize.data_MC(model, data, config=config, figure_folder=figure_folder)

    # Asimov parameter calculation and pre-fit uncertainties
    assert mock_stdev.call_count == 1
    assert mock_asimov.call_args_list[0][0][0] == model
    assert mock_unc.call_count == 1
    assert mock_unc.call_args_list[0][0][0] == model

    # call to stdev calculation
    assert mock_stdev.call_count == 1
    assert mock_stdev.call_args_list[0][0][0] == model
    assert np.allclose(mock_stdev.call_args_list[0][0][1], [1.0, 1.0])
    assert np.allclose(mock_stdev.call_args_list[0][0][2], [0.04956657, 0.0])
    assert np.allclose(mock_stdev.call_args_list[0][0][3],
                       np.asarray([[1.0, 0.0], [0.0, 1.0]]))
    assert mock_stdev.call_args_list[0][1] == {}

    # yield table per bin
    assert mock_table_bin.call_count == 1
    assert mock_table_bin.call_args_list[0][0][0] == model
    assert mock_table_bin.call_args_list[0][0][1] == [[[51.839756]]]
    assert mock_table_bin.call_args_list[0][0][2] == [[0.3]]
    assert mock_table_bin.call_args_list[0][0][3] == [[data[0]]]
    assert mock_table_bin.call_args_list[0][1] == {}

    # yield table per channel
    assert mock_table_channel.call_count == 1
    assert mock_table_channel.call_args_list[0][0][0] == model
    assert mock_table_channel.call_args_list[0][0][1] == [[51.839756]]
    assert mock_table_channel.call_args_list[0][0][2] == [0.3]
    assert mock_table_channel.call_args_list[0][0][3] == [data[0]]
    assert mock_table_channel.call_args_list[0][1] == {}

    assert mock_dict.call_args_list == [[(config, "Signal Region"), {}]]
    assert mock_bins.call_args_list == [[({
        "Name": "region",
        "Variable": "x"
    }, ), {}]]

    expected_histograms = [
        {
            "label": "Signal",
            "isData": False,
            "yields": np.asarray([51.839756]),
            "variable": "x",
        },
        {
            "label": "Data",
            "isData": True,
            "yields": np.asarray(data[:1]),
            "variable": "x",
        },
    ]
    assert mock_draw.call_count == 1
    assert mock_draw.call_args_list[0][0][0] == expected_histograms
    assert np.allclose(mock_draw.call_args_list[0][0][1], np.asarray([0.3]))
    np.testing.assert_equal(mock_draw.call_args_list[0][0][2],
                            np.asarray([1, 2]))
    assert mock_draw.call_args_list[0][0][3] == pathlib.Path(
        "tmp/Signal-Region_prefit.pdf")
    assert mock_draw.call_args_list[0][1] == {
        "log_scale": None,
        "log_scale_x": False
    }

    # post-fit plot and custom scale
    fit_results = fit.FitResults(
        np.asarray([1.01, 1.1]),
        np.asarray([0.03, 0.1]),
        [],
        np.asarray([[1.0, 0.2], [0.2, 1.0]]),
        0.0,
    )
    visualize.data_MC(
        model,
        data,
        config=config,
        figure_folder=figure_folder,
        fit_results=fit_results,
        log_scale=False,
    )

    assert mock_asimov.call_count == 1  # no new call

    # call to stdev calculation
    assert mock_stdev.call_count == 2
    assert mock_stdev.call_args_list[1][0][0] == model
    assert np.allclose(mock_stdev.call_args_list[1][0][1], [1.01, 1.1])
    assert np.allclose(mock_stdev.call_args_list[1][0][2], [0.03, 0.1])
    assert np.allclose(mock_stdev.call_args_list[1][0][3],
                       np.asarray([[1.0, 0.2], [0.2, 1.0]]))
    assert mock_stdev.call_args_list[1][1] == {}

    assert mock_draw.call_count == 2
    # yield at best-fit point is different from pre-fit
    assert np.allclose(mock_draw.call_args_list[1][0][0][0]["yields"],
                       57.59396892)
    assert np.allclose(mock_draw.call_args_list[1][0][1], np.asarray([0.3]))
    np.testing.assert_equal(mock_draw.call_args_list[1][0][2],
                            np.asarray([1, 2]))
    assert mock_draw.call_args_list[1][0][3] == pathlib.Path(
        "tmp/Signal-Region_postfit.pdf")
    assert mock_draw.call_args_list[1][1] == {
        "log_scale": False,
        "log_scale_x": False
    }

    # no yield table
    visualize.data_MC(model, data, config=config, include_table=False)
    assert mock_table_bin.call_count == 2  # 2 calls from before
    assert mock_table_channel.call_count == 2

    # no config specified, default variable name and bin edges, data without auxdata
    visualize.data_MC(model, data[:1])
    assert mock_draw.call_args[0][0][0]["variable"] == "bin"
    assert mock_draw.call_args[0][0][1]["variable"] == "bin"
    assert mock_draw.call_args[0][0][1]["yields"] == np.asarray(data[:1])
    np.testing.assert_equal(mock_draw.call_args[0][2], np.asarray([0, 1]))

    # unknown plotting method
    with pytest.raises(NotImplementedError, match="unknown backend: unknown"):
        visualize.data_MC(model,
                          data,
                          config=config,
                          figure_folder=figure_folder,
                          method="unknown")
Example #2
0
def test_data_MC(mock_load, mock_draw, tmp_path):
    """contrib.histogram_drawing is only imported depending on the keyword argument,
    so the patch works differently from the patch of load_from_config
    Generally it seems like following the path to the module is preferred, but that
    does not work for the `data_MC_matplotlib` case. For some information see also
    https://docs.python.org/3/library/unittest.mock.html#where-to-patch
    """
    config = {
        "Regions": [{
            "Name": "reg_1",
            "Variable": "x"
        }],
        "Samples": [{
            "Name": "sample_1"
        }],
    }

    visualize.data_MC(config,
                      tmp_path,
                      tmp_path,
                      prefit=True,
                      method="matplotlib")

    # the call_args_list contains calls (outer round brackets), first filled with
    # arguments (inner round brackets) and then keyword arguments
    assert mock_load.call_args_list == [(
        (
            tmp_path,
            {
                "Name": "sample_1"
            },
            {
                "Name": "reg_1",
                "Variable": "x"
            },
            {
                "Name": "nominal"
            },
        ),
        {
            "modified": True
        },
    )]
    assert mock_draw.call_args_list == [((
        [{
            "label": "sample_1",
            "isData": False,
            "hist": {},
            "variable": "x"
        }],
        tmp_path / "reg_1_prefit.pdf",
    ), )]

    # other plotting method
    with pytest.raises(NotImplementedError, match="unknown backend") as e_info:
        visualize.data_MC(config,
                          tmp_path,
                          tmp_path,
                          prefit=True,
                          method="unknown")

    # postfit
    with pytest.raises(NotImplementedError,
                       match="only prefit implemented so far") as e_info:
        visualize.data_MC(config,
                          tmp_path,
                          tmp_path,
                          prefit=False,
                          method="matplotlib")
def test_data_MC(
    mock_asimov,
    mock_unc,
    mock_stdev,
    mock_table,
    mock_dict,
    mock_bins,
    mock_draw,
    example_spec,
):
    config = {}
    figure_folder = "tmp"
    model_spec = pyhf.Workspace(example_spec).model().spec

    # pre-fit plot
    visualize.data_MC(config, example_spec, figure_folder=figure_folder)

    # Asimov parameter calculation and pre-fit uncertainties
    assert mock_stdev.call_count == 1
    assert mock_asimov.call_args_list[0][0][0].spec == model_spec
    assert mock_unc.call_count == 1
    assert mock_unc.call_args_list[0][0][0].spec == model_spec

    # call to stdev calculation
    assert mock_stdev.call_count == 1
    assert mock_stdev.call_args_list[0][0][0].spec == model_spec
    assert np.allclose(mock_stdev.call_args_list[0][0][1], [1.0, 1.0])
    assert np.allclose(mock_stdev.call_args_list[0][0][2], [0.04956657, 0.0])
    assert np.allclose(
        mock_stdev.call_args_list[0][0][3], np.asarray([[1.0, 0.0], [0.0, 1.0]])
    )
    assert mock_stdev.call_args_list[0][1] == {}

    # yield table
    assert mock_table.call_count == 1
    assert mock_table.call_args_list[0][0][0].spec == model_spec
    assert mock_table.call_args_list[0][0][1] == [np.asarray([[51.839756]])]
    assert mock_table.call_args_list[0][0][2] == [[0.3]]
    assert mock_table.call_args_list[0][0][3] == [np.asarray([475])]
    assert mock_table.call_args_list[0][1] == {}

    assert mock_dict.call_args_list == [[(config, "Signal Region"), {}]]
    assert mock_bins.call_args_list == [[({"Name": "region", "Variable": "x"},), {}]]

    expected_histograms = [
        {
            "label": "Signal",
            "isData": False,
            "yields": np.asarray([51.839756]),
            "variable": "x",
        },
        {
            "label": "Data",
            "isData": True,
            "yields": np.asarray([475]),
            "variable": "x",
        },
    ]
    assert mock_draw.call_count == 1
    assert mock_draw.call_args_list[0][0][0] == expected_histograms
    assert np.allclose(mock_draw.call_args_list[0][0][1], np.asarray([0.3]))
    assert np.allclose(mock_draw.call_args_list[0][0][2], np.asarray([1, 2]))
    assert mock_draw.call_args_list[0][0][3] == pathlib.Path(
        "tmp/Signal-Region_prefit.pdf"
    )
    assert mock_draw.call_args_list[0][1] == {"log_scale": None}

    # post-fit plot and custom scale
    fit_results = fit.FitResults(
        np.asarray([1.01, 1.1]),
        np.asarray([0.03, 0.1]),
        [],
        np.asarray([[1.0, 0.2], [0.2, 1.0]]),
        0.0,
    )
    visualize.data_MC(
        config,
        example_spec,
        figure_folder=figure_folder,
        fit_results=fit_results,
        log_scale=False,
    )

    assert mock_asimov.call_count == 1  # no new call

    # call to stdev calculation
    assert mock_stdev.call_count == 2
    assert mock_stdev.call_args_list[1][0][0].spec == model_spec
    assert np.allclose(mock_stdev.call_args_list[1][0][1], [1.01, 1.1])
    assert np.allclose(mock_stdev.call_args_list[1][0][2], [0.03, 0.1])
    assert np.allclose(
        mock_stdev.call_args_list[1][0][3], np.asarray([[1.0, 0.2], [0.2, 1.0]])
    )
    assert mock_stdev.call_args_list[1][1] == {}

    assert mock_draw.call_count == 2
    # yield at best-fit point is different from pre-fit
    assert np.allclose(mock_draw.call_args_list[1][0][0][0]["yields"], 57.59396892)
    assert np.allclose(mock_draw.call_args_list[1][0][1], np.asarray([0.3]))
    assert np.allclose(mock_draw.call_args_list[1][0][2], np.asarray([1, 2]))
    assert mock_draw.call_args_list[1][0][3] == pathlib.Path(
        "tmp/Signal-Region_postfit.pdf"
    )
    assert mock_draw.call_args_list[1][1] == {"log_scale": False}

    # no yield table
    visualize.data_MC(config, example_spec, include_table=False)
    assert mock_table.call_count == 2  # 2 calls from before

    # unknown plotting method
    with pytest.raises(NotImplementedError, match="unknown backend: unknown"):
        visualize.data_MC(
            config, example_spec, figure_folder=figure_folder, method="unknown"
        )