{"id":13858257,"url":"https://github.com/leeper/make-example","last_synced_at":"2025-03-23T14:31:46.948Z","repository":{"id":70769762,"uuid":"68825655","full_name":"leeper/make-example","owner":"leeper","description":"An example of using make for a data analysis project","archived":false,"fork":false,"pushed_at":"2019-05-06T11:30:29.000Z","size":28,"stargazers_count":33,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-02T01:36:24.609Z","etag":null,"topics":["data-analysis","make","manuscript","reproducible-research"],"latest_commit_sha":null,"homepage":null,"language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leeper.png","metadata":{"files":{"readme":"README.Rmd","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2016-09-21T14:32:18.000Z","updated_at":"2025-01-14T16:17:59.000Z","dependencies_parsed_at":"2023-05-15T12:15:46.468Z","dependency_job_id":null,"html_url":"https://github.com/leeper/make-example","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leeper%2Fmake-example","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leeper%2Fmake-example/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leeper%2Fmake-example/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leeper%2Fmake-example/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leeper","download_url":"https://codeload.github.com/leeper/make-example/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244306141,"owners_count":20431747,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-analysis","make","manuscript","reproducible-research"],"created_at":"2024-08-05T03:02:02.023Z","updated_at":"2025-03-23T14:31:46.579Z","avatar_url":"https://github.com/leeper.png","language":"R","funding_links":[],"categories":["R"],"sub_categories":[],"readme":"# Example of `make` for data analysis\n\nThis repository shows how to use `make` for a data analysis project.\n\nThe paper (PDF) is generated from a LaTeX source file, a table, and a figure.\n\n`make` uses a set of instructions in `makefile` to generate the table and figure using R code and a datafile, and then generate the PDF from the manuscript.\n\n`make` is clever because it deconstructs each part of the analysis so that only parts that have changed need to be rerun. If the data change, everything is rerun. If figure-generating code changes, only that code and the manuscript are rerun. If only the manuscript changes, only `pdflatex` is rerun. It's smart like that.\n\nBasically it works on a directed acyclic graph (DAG) model, represented by this network graph:\n\n```{r setup, include=FALSE}\nlibrary(\"svglite\")\nknitr::opts_chunk$set(\n  dev = \"svglite\",\n  fig.path=\"fig-\",\n  fig.ext = \"svg\"\n)\n```\n\n```{r dag, echo = FALSE, fig.height=4, fig.width=6}\nrequireNamespace(\"igraph\", quietly = TRUE)\nrequireNamespace(\"ggraph\", quietly = TRUE)\n\nparse_makefile \u003c-\nfunction(\n  file = \"makefile\",\n  ...\n) {\n    con \u003c- file(file, open = \"rb\")\n    on.exit(close(con))\n    m \u003c- character()\n    # handle continuation characters\n    while (length(con)) {\n        this_line \u003c- readLines(con, n = 1L)\n        if (!length(this_line)) {\n            break\n        }\n        m[length(m) + 1] \u003c- this_line\n        while (grepl(\"\\\\\\\\$\", m[length(m)]) \u0026\u0026 length(con)) {\n            m[length(m)] \u003c- sub(\"\\\\\\\\$\", \" \", m[length(m)])\n            m[length(m)] \u003c- paste0(m[length(m)], readLines(con, n = 1L))\n        }\n    }\n    return(m)\n}\n\nmakefile_to_network \u003c-\nfunction(\n  lines = parse_makefile(),\n  exclude = NULL,\n  ...\n) {\n    rules \u003c- lines[grepl(\"[ A-Za-z0-9./]+ ?[:] ?[ A-Za-z0-9./]+\", lines)]\n    rules_list \u003c- strsplit(rules, \" ?: ?\")\n    edges \u003c- lapply(rules_list, function(x) {\n        # cleanup target\n        target \u003c- x[1L]\n        if (target %in% exclude) {\n            return(NULL)\n        }\n        ## handle targets with multiple outputs\n        targets \u003c- strsplit(target, \" \")[[1L]]\n        \n        # cleanup prereqs\n        prereqs \u003c- strsplit(x[2L], \"[ \\t]+\")[[1L]]\n        prereqs \u003c- prereqs[!is.na(prereqs)]\n        \n        # return\n        if (!length(prereqs) || all(prereqs == \"\")) {\n            return(NULL)\n        }\n        as.vector(t(as.matrix((expand.grid(prereqs, targets, stringsAsFactors = FALSE)))))\n    })\n    igraph::make_graph(unlist(edges))\n}\n\nnet \u003c- makefile_to_network(parse_makefile(\"makefile\"), exclude = \"all\")\nggraph::ggraph(net, layout = \"kk\") + \n  ggraph::geom_edge_link(ggplot2::aes(start_cap = ggraph::label_rect(node1.name),\n                                      end_cap = ggraph::label_rect(node2.name)), \n                         arrow = grid::arrow(length = grid::unit(2, 'mm'))) + \n  ggraph::geom_node_text(ggplot2::aes(label = name), size = 4) +\n  ggplot2::theme_void()\n```\n\nThe R file `analysis.R` shows what is going on in `makefile` using possibly more familiar R syntax. The `README.Rmd` file contains the code to construct the above graph from an arbitrary makefile.\n\nZach Jones has [a good tutorial](http://zmjones.com/make/) about all of this.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleeper%2Fmake-example","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleeper%2Fmake-example","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleeper%2Fmake-example/lists"}