def test_tree_to_grid_vcat_hcat(): """ Tests that the tree_to_grid function returns the correct answer when a single plot is vertically concatenated with two horizontally concatenated plots. """ tree = {"vcat": [{"plot": 1}, {"hcat": [{"plot": 2}, {"plot": 3}]}]} truth = [ { "plot": 1, "row_start": 0, "row_end": 1, "column_start": 0, "column_end": 2, }, { "plot": 2, "row_start": 1, "row_end": 2, "column_start": 0, "column_end": 1, }, { "plot": 3, "row_start": 1, "row_end": 2, "column_start": 1, "column_end": 2, }, ] answer = tree_to_grid(tree) assert truth == answer
def test_tree_to_grid_multiple_plots_vcat(): """ Tests that the tree_to_grid function returns the correct value when the tree contains multiple vcat plots. """ tree = {"vcat": [{"plot": 1}, {"plot": 2}]} truth = [ { "plot": 1, "row_start": 0, "row_end": 1, "column_start": 0, "column_end": 1, }, { "plot": 2, "row_start": 1, "row_end": 2, "column_start": 0, "column_end": 1, }, ] answer = tree_to_grid(tree) assert truth == answer
def test_tree_to_grid_stacked_hcats(): """ Tests that the tree_to_grid function returns the correct value for multilayered hcats. """ tree = {"hcat": [{"plot": 1}, {"hcat": [{"plot": 2}, {"plot": 3}]}]} truth = [ { "plot": 1, "row_start": 0, "row_end": 1, "column_start": 0, "column_end": 2, }, { "plot": 2, "row_start": 0, "row_end": 1, "column_start": 2, "column_end": 3, }, { "plot": 3, "row_start": 0, "row_end": 1, "column_start": 3, "column_end": 4, }, ] answer = tree_to_grid(tree) assert truth == answer
def test_tree_to_grid_multiple_plots_hcat(): """ Tests that the tree_to_grid function returns the correct value when there are multiple horizontally concatenated plots. """ tree = {"hcat": [{"plot": 1}, {"plot": 2}, {"plot": 3}]} truth = [ { "plot": 1, "row_start": 0, "row_end": 1, "column_start": 0, "column_end": 1, }, { "plot": 2, "row_start": 0, "row_end": 1, "column_start": 1, "column_end": 2, }, { "plot": 3, "row_start": 0, "row_end": 1, "column_start": 2, "column_end": 3, }, ] answer = tree_to_grid(tree) assert truth == answer
def test_tree_to_grid_regular_grid_hcat(): """ Tests that the tree_to_grid function returns the correct value when the plots are placed on a regular 2x2 grid with horizontal concatenation. """ tree = { "hcat": [ { "vcat": [{ "plot": 1 }, { "plot": 2 }] }, { "vcat": [{ "plot": 3 }, { "plot": 4 }] }, ] } truth = [ { "plot": 1, "row_start": 0, "row_end": 1, "column_start": 0, "column_end": 1, }, { "plot": 2, "row_start": 1, "row_end": 2, "column_start": 0, "column_end": 1, }, { "plot": 3, "row_start": 0, "row_end": 1, "column_start": 1, "column_end": 2, }, { "plot": 4, "row_start": 1, "row_end": 2, "column_start": 1, "column_end": 2, }, ] answer = tree_to_grid(tree) assert truth == answer
def test_tree_to_grid_mixed_vcat_hcat(): """ Tests that the tree_to_grid function returns the correct value when there are mixed vcats and hcats. """ tree = { "vcat": [ { "hcat": [{ "plot": 1 }, { "plot": 2 }] }, { "vcat": [{ "plot": 3 }, { "plot": 4 }] }, ] } truth = [ { "plot": 1, "row_start": 0, "row_end": 2, "column_start": 0, "column_end": 1, }, { "plot": 2, "row_start": 0, "row_end": 2, "column_start": 1, "column_end": 2, }, { "plot": 3, "row_start": 2, "row_end": 3, "column_start": 0, "column_end": 2, }, { "plot": 4, "row_start": 3, "row_end": 4, "column_start": 0, "column_end": 2, }, ] answer = tree_to_grid(tree) assert truth == answer
def test_tree_to_grid_single_plot_vcat(): """ Tests that the tree_to_grid function works for a single plot. """ tree = {"vcat": [{"plot": 1}]} answer = [{ "plot": 1, "row_start": 0, "row_end": 1, "column_start": 0, "column_end": 1, }] truth = tree_to_grid(tree) assert truth == answer
def test_tree_to_grid_single_plot_hcat(): """ Tests that the tree_to_grid function works correctly for a single hcat plot. """ tree = {"hcat": [{"plot": 1}]} truth = [{ "plot": 1, "row_start": 0, "row_end": 1, "column_start": 0, "column_end": 1, }] answer = tree_to_grid(tree) assert truth == answer
def svl(svl_source, backend="plotly", datasets=[], offline_js=False, debug=False): """ Compiles the SVL source into a rendered plot template. Parameters ----------- svl_source : str The SVL source code. backend : str Which plotting backend to render the plots with. Default: "plotly". datasets : list[str] A list of additional datasets to inject into the ast, for datasets not present in the SVL source code. Each dataset specifier must be of the form "dataset_name=dataset_location". offline_js : bool Whether to embed the javascript into the final HTML directly. Default: False. debug : bool If this flag is true, return the pretty-printed parse tree instead of the compiled program. Returns ------- str The rendered HTML template for the plots. Raises ------ ValueError If there is a malformed additional dataset specifier. SvlSyntaxError If there is a syntax error in the SVL source. SvlMissingFileError If there is a missing file in the SVL source or additional datasets. SvlMissingDatasetError If there is a dataset specified in a plot that isn't in the dataset specifiers for the SVL program. SvlPlotError If there is an error in any of the SVL plots. SvlDataLoadError If there is an error loading the data into sqlite. SvlDataProcessingError If there is an error processing the plot data. NotImplementedError If a backend is selected that hasn't been implemented. """ if debug: return parse_svl(svl_source, debug=True).pretty() for dataset in datasets: if len(dataset.split("=")) != 2: raise ValueError( "dataset {} needs to be name=path".format(dataset)) additional_datasets = _extract_additional_datasets(datasets) try: svl_ast = parse_svl(svl_source, **additional_datasets) except SvlSyntaxError as e: raise e # Validate that all of the files exist that need to exist. for _, dataset in svl_ast["datasets"].items(): if ("file" in dataset) and (not os.path.exists(dataset["file"])): raise SvlMissingFileError("File {} does not exist.".format( dataset["file"])) # Flatten the AST plot representation into a list with grid coordinates. svl_plots = tree_to_grid(svl_ast) # Validate the plots. for plot in svl_plots: # Each plot must point to a dataset that exists. if plot["data"] not in svl_ast["datasets"]: existing_dataset = ", ".join(list(svl_ast["datasets"].keys())) raise SvlMissingDatasetError( "Dataset {} is not in provided datasets {}.".format( plot["data"], existing_dataset)) # Each plot must be a valid specification. ok, msg = validate_plot(plot) if not ok: raise SvlPlotError("Plot error: {}".format(msg)) # Set up the connection to sqlite. Eventually this will be abstracted since # in principle we could have other data sources but for now sqlite is what # we've got. try: sqlite_conn = create_datasets(svl_ast["datasets"]) except sqlite3.DatabaseError as e: raise SvlDataLoadError("Error loading data: {}.".format(e)) # Get the data for the plots. try: svl_plot_data = [get_svl_data(plot, sqlite_conn) for plot in svl_plots] except sqlite3.DatabaseError as e: raise SvlDataProcessingError( "Error processing plot data: {}".format(e)) # Select and render the template. if backend == "plotly": template_vars = plotly_template_vars(svl_plots, svl_plot_data) template = plotly_template() # If offline is selected, use the offline plotly in the template. template_vars["plotly_offline"] = offline_js else: raise NotImplementedError( "Unable to use {} as a backend.".format(backend)) return template.render(**template_vars)
def test_tree_to_grid_doomsday(): """ The gnarliest of tests. """ tree = { "vcat": [ { "hcat": [ { "plot": 1 }, { "vcat": [{ "plot": 2 }, { "plot": 3 }, { "plot": 4 }] }, { "vcat": [ { "plot": 5 }, { "hcat": [{ "plot": 6 }, { "plot": 7 }] }, ] }, { "vcat": [ { "hcat": [{ "plot": 8 }, { "plot": 9 }] }, { "plot": 10 }, ] }, ] }, { "plot": 11 }, ] } truth = [ { "plot": 1, "row_start": 0, "row_end": 6, "column_start": 0, "column_end": 2, }, { "plot": 2, "row_start": 0, "row_end": 2, "column_start": 2, "column_end": 4, }, { "plot": 3, "row_start": 2, "row_end": 4, "column_start": 2, "column_end": 4, }, { "plot": 4, "row_start": 4, "row_end": 6, "column_start": 2, "column_end": 4, }, { "plot": 5, "row_start": 0, "row_end": 3, "column_start": 4, "column_end": 6, }, { "plot": 6, "row_start": 3, "row_end": 6, "column_start": 4, "column_end": 5, }, { "plot": 7, "row_start": 3, "row_end": 6, "column_start": 5, "column_end": 6, }, { "plot": 8, "row_start": 0, "row_end": 3, "column_start": 6, "column_end": 7, }, { "plot": 9, "row_start": 0, "row_end": 3, "column_start": 7, "column_end": 8, }, { "plot": 10, "row_start": 3, "row_end": 6, "column_start": 6, "column_end": 8, }, { "plot": 11, "row_start": 6, "row_end": 12, "column_start": 0, "column_end": 8, }, ] answer = tree_to_grid(tree) assert truth == answer