

{"id":4061,"date":"2016-03-10T18:28:30","date_gmt":"2016-03-10T23:28:30","guid":{"rendered":"http:\/\/rud.is\/b\/?p=4061"},"modified":"2018-03-07T16:42:46","modified_gmt":"2018-03-07T21:42:46","slug":"some-light-image-processing-creation-with-r","status":"publish","type":"post","link":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/","title":{"rendered":"Some Light Image Processing &#038; Creation With R"},"content":{"rendered":"<p>>UPDATE: I rejiggered the function to actually now, y&#8217;know, do what it says it should do :-)<\/p>\n<p>A friend, we&#8217;ll call him _Alen_ put a call out for some function that could take an image and produce a per-row &#8220;histogram&#8221; along the edge for the number of filled-in points. That requirement eventually scope-creeped to wanting &#8220;histograms&#8221; on both the edge and bottom. In, essence there was a desire to be able to compare the number of pixels in each row\/line to each other.<\/p>\n<p>Now, you&#8217;re all like _&#8221;Well, you used ggplot to make the image so\u2026&#8221;_ Yeah, not so much. They had done some basic charting in D3. And, it turns out, that it would be handy to compare the data between different images since they had different sets of data they were charting in the same place. <\/p>\n<p>I can&#8217;t show you their images as they are part of super seekrit research which will eventually solve world hunger and land a family on Mars. But, I _can_ do a minor re-creation. I made a really simple D3 page that draws random lines in a specified color. Like this:<\/p>\n<p><center><br \/>\n<iframe loading=\"lazy\" style=\"max-width=100%\" \n        src=\"http:\/\/rud.is\/projects\/randomlines.html?linecol=f6743d\" \n        sandbox=\"allow-same-origin allow-scripts\" \n        width=\"700\" \n        height=\"450\" \n        scrolling=\"yes\" \n        seamless=\"seamless\" \n        frameBorder=\"0\"><\/iframe><br \/>\n<\/center><\/p>\n<p>You can view the source of <http:\/\/rud.is\/projects\/randomlines.html?linecol=f6743d> to see the dead-simple D3 that generates that. You&#8217;ll see something different in that image every time since it&#8217;s javascript and js has no decent built-in random routines (well it does _now_ but the engine functionality in browsers hasn&#8217;t caught up yet). So, you won&#8217;t be able to 100% replicate the results below but it will work.<\/p>\n<p>First, we need to be able to get the image from the `div` into a bitmap so we can do some pixel counting. We&#8217;ll use the new `webshot` package for that.<\/p>\n<pre lang=\"rsplus\">library(webshot)\r\n\r\ntmppng1 <- tempfile(fileext=\".png\")\r\nwebshot(\"http:\/\/rud.is\/projects\/randomlines.html?linecol=f6743d\", \r\n        file=tmppng1,\r\n        selector=\"#vis\")<\/pre>\n<p>The image that produced looks like this:<\/p>\n<p><a href=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/img1.png?ssl=1\" rel=\"attachment wp-att-4080\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"4080\" data-permalink=\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/img1\/\" data-orig-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/img1.png?fit=700%2C400&amp;ssl=1\" data-orig-size=\"700,400\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"img1\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/img1.png?fit=300%2C171&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/img1.png?fit=510%2C291&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/img1.png?resize=510%2C291&#038;ssl=1\" alt=\"img1\" width=\"510\" height=\"291\" class=\"aligncenter size-full wp-image-4080\" \/><\/a><\/p>\n<p>To make the \"histograms\" on the right and bottom, we'll use the `raster` capabilities in R to let us treat the data like a matrix so we can easily add columns and rows. I made a function (below) that takes in a `png` file and either a list of colors to look for or a list of colors to exclude and the color you want the \"histograms\" to be drawn in. This way you can just exclude the background and annotation colors or count specific sets of colors. The counting is fueled by `fastmatch` which makes for super-fast comparisons.<\/p>\n<pre lang=\"rsplus\">#' Make a \"row color density\" histogram for an image file\r\n#' \r\n#' Takes a file path to a png and returns displays it with a histogram of \r\n#' pixel density\r\n#' \r\n#' @param img_file path to png file\r\n#' @param target_colors,ignore_colors colors to count or ignore. Either one should be \r\n#'        \\code{NULL} or \\code{ignore_colors} should be \\code{NULL}. Whichever is\r\n#'        not \\code{NULL} should be a vector of hex strings (can be huge vector of \r\n#'        hex strings as it uses \\code{fastmatch}). The alpha channel is thrown away \r\n#'        if any, so you only need to specify \\code{#rrggbb} hex strings\r\n#' @param color to use for the density histogram line\r\nselective_image_color_histogram <- function(img_file, \r\n                                            target_colors=NULL,\r\n                                            ignore_colors=c(\"#ffffff\", \"#000000\"),\r\n                                            hist_col=\"steelblue\",\r\n                                            plot=TRUE) {\r\n  \r\n  require(png)\r\n  require(grid)\r\n  require(raster)\r\n  require(fastmatch)\r\n  require(gridExtra)\r\n\r\n  \"%fmin%\" <- function(x, table) { fmatch(x, table, nomatch = 0) > 0 }\r\n  \"%!fmin%\" <- function(x, table) { !fmatch(x, table, nomatch = 0) > 0 }\r\n  \r\n  if (is.null(target_colors) & is.null(ignore_colors)) {\r\n    stop(\"Only one of 'target_colors' or 'ignore_colors' can be 'NULL'\", call.=FALSE)\r\n  }\r\n  \r\n  # clean up params\r\n  target_colors <- tolower(target_colors)  \r\n  ignore_colors <- tolower(ignore_colors)  \r\n  \r\n  # read in file and convert to usable data structure  \r\n  png_file <- readPNG(img_file)\r\n  img <- substr(tolower(as.matrix(as.raster(png_file))), 1, 7)\r\n  \r\n  if (length(target_colors)==0) {\r\n    tf_img <- matrix(img %!fmin% ignore_colors, nrow=nrow(img), ncol=ncol(img))\r\n  } else {\r\n    tf_img <- matrix(img %fmin% target_colors, nrow=nrow(img), ncol=ncol(img))\r\n  }  \r\n\r\n  # count the pixels\r\n  wvals <- rowSums(tf_img)\r\n  hvals <- colSums(tf_img)\r\n\r\n  # add a slight right &#038; bottom margin\r\n  wdth <- max(wvals) + round(0.1*max(wvals))\r\n  hght <- max(hvals) + round(0.1*max(hvals))\r\n  \r\n  # create the \"histogram\" \r\n  col_mat <- matrix(rep(\"#ffffff\", wdth*nrow(img)), nrow=nrow(img), ncol=wdth)\r\n  for (row in 1:nrow(img)) { \r\n    col_mat[row, 1:wvals[row]] <- hist_col\r\n  }\r\n  \r\n  # make bigger image\r\n  new_img <- cbind(img, col_mat)\r\n  \r\n  # create the \"histogram\"\r\n  row_mat <- matrix(rep(\"#ffffff\", hght*ncol(new_img)), ncol=ncol(new_img), nrow=hght)\r\n  for (col in 1:ncol(img)) { \r\n    row_mat[1:hvals[col], col] <- hist_col\r\n  }\r\n  \r\n  # make a new bigger image and turn it into something we can use with \r\n  # grid since we can also use it with ggplot this way if we really wanted to\r\n  # and friends don't let friends use base graphics\r\n  rg1 <- rasterGrob(rbind(new_img, row_mat))\r\n  \r\n  # if we want to plot it, now is the time\r\n  if (plot) grid.arrange(rg1)\r\n  \r\n  # return a list with each \"histogram\"\r\n  return(list(row_hist=wvals, col_hist=hvals))\r\n  \r\n}<\/pre>\n<p>After reading in the `png` as a raster, the function counts up all the specified pixels by row and extends the matrix width-wise. Then it does the same by column and extends the matrix height-wise. Finally, it makes a `rasterGrob` (b\/c friends don't let friends use base graphics) and optionally plots the output. It also returns the counts by row and by column. That will let us compare between images.<\/p>\n<p>Now we can do:<\/p>\n<pre lang=\"rsplus\">a <- selective_image_color_histogram(tmppng, hist_col=\"#f6743d\", plot=TRUE)<\/pre>\n<p><a href=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1-1.png?ssl=1\" rel=\"attachment wp-att-4081\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"4081\" data-permalink=\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/hist1-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1-1.png?fit=900%2C500&amp;ssl=1\" data-orig-size=\"900,500\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"hist1\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1-1.png?fit=300%2C167&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1-1.png?fit=510%2C283&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1-1.png?resize=510%2C283&#038;ssl=1\" alt=\"hist1\" width=\"510\" height=\"283\" class=\"aligncenter size-full wp-image-4081\" \/><\/a><\/p>\n<p>And, make a counterpart image for it:<\/p>\n<pre lang=\"rsplus\">tmppng2 <- tempfile(fileext=\".png\")\r\nwebshot(\"http:\/\/rud.is\/projects\/randomlines.html?linecol=80b1d4\", \r\n        file=tmppng2,\r\n        selector=\"#vis\")\r\n\r\nb <- selective_image_color_histogram(tmppng2, hist_col=\"#80b1d4\", plot=TRUE)<\/pre>\n<p><a href=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist2.png?ssl=1\" rel=\"attachment wp-att-4083\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"4083\" data-permalink=\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/hist2\/\" data-orig-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist2.png?fit=900%2C500&amp;ssl=1\" data-orig-size=\"900,500\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"hist2\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist2.png?fit=300%2C167&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist2.png?fit=510%2C283&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist2.png?resize=510%2C283&#038;ssl=1\" alt=\"hist2\" width=\"510\" height=\"283\" class=\"aligncenter size-full wp-image-4083\" \/><\/a><\/p>\n<p>You can definitely visually compare to see which ones had more \"activity\" in which row(s) (or column(s)) but why not let R do that for you (you'll probably need to change the font to something boring like `\"Helvetica\"`)?<\/p>\n<pre lang=\"rsplus\">library(ggplot2)\r\nlibrary(dplyr)\r\n\r\ngg <- ggplot(data_frame(x=1:length(a$row_hist),\r\n                        diff=a$row_hist - b$row_hist,\r\n                        `A vs B`=factor(sign(diff), levels=c(-1, 0, 1), \r\n                                        labels=c(\"A\", \"Neutral\", \"B\"))))\r\ngg <- gg + geom_segment(aes(x=x, xend=x, y=0, yend=diff, color=`A vs B`))\r\ngg <- gg + scale_x_continuous(expand=c(0,0))\r\ngg <- gg + scale_y_continuous(expand=c(0,0))\r\ngg <- gg + scale_color_manual(values=c(\"#f6743d\", \"#2b2b2b\", \"#80b1d4\"))\r\ngg <- gg + labs(x=\"Row\", y=\"Difference\")\r\ngg <- gg + coord_flip()\r\ngg <- gg + ggthemes::theme_tufte(base_family=\"URW Geometric Semi Bold\")\r\ngg <- gg + theme(panel.grid=element_line(color=\"#2b2b2b\", size=0.15))\r\ngg <- gg + theme(panel.grid.major.y=element_blank())\r\ngg <- gg + theme(panel.grid.minor=element_blank())\r\ngg <- gg + theme(axis.ticks=element_blank())\r\ngg <- gg + theme(axis.text.y=element_blank())\r\ngg <- gg + theme(axis.title.x=element_text(hjust=0))\r\ngg <- gg + theme(axis.title.y=element_text(hjust=0))\r\ngg<\/pre>\n<p><a href=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/vertdif.png?ssl=1\" rel=\"attachment wp-att-4079\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" data-attachment-id=\"4079\" data-permalink=\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/vertdif\/\" data-orig-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/vertdif.png?fit=1368%2C1322&amp;ssl=1\" data-orig-size=\"1368,1322\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"vertdif\" data-image-description=\"\" data-image-caption=\"\" data-medium-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/vertdif.png?fit=300%2C290&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/vertdif.png?fit=510%2C493&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/vertdif.png?resize=510%2C493&#038;ssl=1\" alt=\"vertdif\" width=\"510\" height=\"493\" class=\"aligncenter size-full wp-image-4079\" \/><\/a><\/p>\n<p>This way, you let the _power of data science_ show you the answer. (The column processing chart is an exercise left to the reader).<\/p>\n<p>The code may only be useful to _Alen_, but it was a fun and quick enough exercise that I thought it might be useful to the broader community.<\/p>\n<p>Poke holes or improve upon it at will and tell me how horrible my code is in the comments (I have not looked to see if I subtracted in the right direction as I'm on solo dad duty for a cpl days and #4 is hungry).<\/p>\n","protected":false},"excerpt":{"rendered":"<p>>UPDATE: I rejiggered the function to actually now, y&#8217;know, do what it says it should do :-) A friend, we&#8217;ll call him _Alen_ put a call out for some function that could take an image and produce a per-row &#8220;histogram&#8221; along the edge for the number of filled-in points. That requirement eventually scope-creeped to wanting [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":4078,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":3,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":""},"categories":[666,678,673,674,753,724,91],"tags":[810],"class_list":["post-4061","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-d3","category-data-visualization","category-datavis-2","category-dataviz","category-ggplot","category-phantomjs","category-r","tag-post"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.2 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Some Light Image Processing &amp; Creation With R - rud.is<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Some Light Image Processing &amp; Creation With R - rud.is\" \/>\n<meta property=\"og:description\" content=\"&gt;UPDATE: I rejiggered the function to actually now, y&#8217;know, do what it says it should do :-) A friend, we&#8217;ll call him _Alen_ put a call out for some function that could take an image and produce a per-row &#8220;histogram&#8221; along the edge for the number of filled-in points. That requirement eventually scope-creeped to wanting [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/\" \/>\n<meta property=\"og:site_name\" content=\"rud.is\" \/>\n<meta property=\"article:published_time\" content=\"2016-03-10T23:28:30+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2018-03-07T21:42:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1.png?fit=900%2C500&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"900\" \/>\n\t<meta property=\"og:image:height\" content=\"500\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"hrbrmstr\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"hrbrmstr\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/\"},\"author\":{\"name\":\"hrbrmstr\",\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\"},\"headline\":\"Some Light Image Processing &#038; Creation With R\",\"datePublished\":\"2016-03-10T23:28:30+00:00\",\"dateModified\":\"2018-03-07T21:42:46+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/\"},\"wordCount\":627,\"commentCount\":5,\"publisher\":{\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\"},\"image\":{\"@id\":\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1.png?fit=900%2C500&ssl=1\",\"keywords\":[\"post\"],\"articleSection\":[\"d3\",\"Data Visualization\",\"DataVis\",\"DataViz\",\"ggplot\",\"phantomjs\",\"R\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/\",\"url\":\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/\",\"name\":\"Some Light Image Processing & Creation With R - rud.is\",\"isPartOf\":{\"@id\":\"https:\/\/rud.is\/b\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1.png?fit=900%2C500&ssl=1\",\"datePublished\":\"2016-03-10T23:28:30+00:00\",\"dateModified\":\"2018-03-07T21:42:46+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#primaryimage\",\"url\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1.png?fit=900%2C500&ssl=1\",\"contentUrl\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1.png?fit=900%2C500&ssl=1\",\"width\":900,\"height\":500},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/rud.is\/b\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Some Light Image Processing &#038; Creation With R\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/rud.is\/b\/#website\",\"url\":\"https:\/\/rud.is\/b\/\",\"name\":\"rud.is\",\"description\":\"&quot;In God we trust. All others must bring data&quot;\",\"publisher\":{\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/rud.is\/b\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886\",\"name\":\"hrbrmstr\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\",\"url\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\",\"contentUrl\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\",\"width\":460,\"height\":460,\"caption\":\"hrbrmstr\"},\"logo\":{\"@id\":\"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1\"},\"description\":\"Don't look at me\u2026I do what he does \u2014 just slower. #rstats avuncular \u2022 ?Resistance Fighter \u2022 Cook \u2022 Christian \u2022 [Master] Chef des Donn\u00e9es de S\u00e9curit\u00e9 @ @rapid7\",\"sameAs\":[\"http:\/\/rud.is\"],\"url\":\"https:\/\/rud.is\/b\/author\/hrbrmstr\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Some Light Image Processing & Creation With R - rud.is","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/","og_locale":"en_US","og_type":"article","og_title":"Some Light Image Processing & Creation With R - rud.is","og_description":">UPDATE: I rejiggered the function to actually now, y&#8217;know, do what it says it should do :-) A friend, we&#8217;ll call him _Alen_ put a call out for some function that could take an image and produce a per-row &#8220;histogram&#8221; along the edge for the number of filled-in points. That requirement eventually scope-creeped to wanting [&hellip;]","og_url":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/","og_site_name":"rud.is","article_published_time":"2016-03-10T23:28:30+00:00","article_modified_time":"2018-03-07T21:42:46+00:00","og_image":[{"width":900,"height":500,"url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1.png?fit=900%2C500&ssl=1","type":"image\/png"}],"author":"hrbrmstr","twitter_card":"summary_large_image","twitter_misc":{"Written by":"hrbrmstr","Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#article","isPartOf":{"@id":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/"},"author":{"name":"hrbrmstr","@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"headline":"Some Light Image Processing &#038; Creation With R","datePublished":"2016-03-10T23:28:30+00:00","dateModified":"2018-03-07T21:42:46+00:00","mainEntityOfPage":{"@id":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/"},"wordCount":627,"commentCount":5,"publisher":{"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"image":{"@id":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1.png?fit=900%2C500&ssl=1","keywords":["post"],"articleSection":["d3","Data Visualization","DataVis","DataViz","ggplot","phantomjs","R"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/","url":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/","name":"Some Light Image Processing & Creation With R - rud.is","isPartOf":{"@id":"https:\/\/rud.is\/b\/#website"},"primaryImageOfPage":{"@id":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#primaryimage"},"image":{"@id":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1.png?fit=900%2C500&ssl=1","datePublished":"2016-03-10T23:28:30+00:00","dateModified":"2018-03-07T21:42:46+00:00","breadcrumb":{"@id":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#primaryimage","url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1.png?fit=900%2C500&ssl=1","contentUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1.png?fit=900%2C500&ssl=1","width":900,"height":500},{"@type":"BreadcrumbList","@id":"https:\/\/rud.is\/b\/2016\/03\/10\/some-light-image-processing-creation-with-r\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/rud.is\/b\/"},{"@type":"ListItem","position":2,"name":"Some Light Image Processing &#038; Creation With R"}]},{"@type":"WebSite","@id":"https:\/\/rud.is\/b\/#website","url":"https:\/\/rud.is\/b\/","name":"rud.is","description":"&quot;In God we trust. All others must bring data&quot;","publisher":{"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/rud.is\/b\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886","name":"hrbrmstr","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","contentUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","width":460,"height":460,"caption":"hrbrmstr"},"logo":{"@id":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1"},"description":"Don't look at me\u2026I do what he does \u2014 just slower. #rstats avuncular \u2022 ?Resistance Fighter \u2022 Cook \u2022 Christian \u2022 [Master] Chef des Donn\u00e9es de S\u00e9curit\u00e9 @ @rapid7","sameAs":["http:\/\/rud.is"],"url":"https:\/\/rud.is\/b\/author\/hrbrmstr\/"}]}},"jetpack_featured_media_url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/03\/hist1.png?fit=900%2C500&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p23idr-13v","jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":3054,"url":"https:\/\/rud.is\/b\/2014\/09\/26\/overcoming-d3-cartographic-envy-with-r-ggplot\/","url_meta":{"origin":4061,"position":0},"title":"Overcoming D3 Cartographic Envy With R + ggplot","author":"hrbrmstr","date":"2014-09-26","format":false,"excerpt":"When I used one of the Scotland TopoJSON files for a recent post, it really hit me just how much D3 cartography envy I had\/have as an R user. Don't get me wrong, I can conjure up D3 maps pretty well [1] [2] and the utility of an interactive map\u2026","rel":"","context":"In &quot;Charts &amp; Graphs&quot;","block_context":{"text":"Charts &amp; Graphs","link":"https:\/\/rud.is\/b\/category\/charts-graphs\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3028,"url":"https:\/\/rud.is\/b\/2014\/09\/20\/chartingmapping-the-scottish-vote-with-r-rvestdplyrtidyrtopojsonggplot\/","url_meta":{"origin":4061,"position":1},"title":"Charting\/Mapping the Scottish Vote with R (an rvest\/dplyr\/tidyr\/TopoJSON\/ggplot tutorial)","author":"hrbrmstr","date":"2014-09-20","format":false,"excerpt":"The BBC did a pretty good job [live tracking the Scotland secession vote](http:\/\/www.bbc.com\/news\/events\/scotland-decides\/results), but I really didn't like the color scheme they chose and decided to use the final tally site as the basis for another tutorial using the tools from the Hadleyverse and taking advantage of the fact that\u2026","rel":"","context":"In &quot;Charts &amp; Graphs&quot;","block_context":{"text":"Charts &amp; Graphs","link":"https:\/\/rud.is\/b\/category\/charts-graphs\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3498,"url":"https:\/\/rud.is\/b\/2015\/07\/09\/faceted-world-population-by-income-choropleths-in-ggplot\/","url_meta":{"origin":4061,"position":2},"title":"Faceted &#8220;World Population by Income&#8221; Choropleths in ggplot","author":"hrbrmstr","date":"2015-07-09","format":false,"excerpt":"Poynter did a nice interactive piece on world population by income (i.e. \"How Many Live on How Much, and Where\"). I'm always on the lookout for optimized shapefiles and clean data (I'm teaching a data science certificate program starting this Fall) and the speed of the site load and the\u2026","rel":"","context":"In &quot;cartography&quot;","block_context":{"text":"cartography","link":"https:\/\/rud.is\/b\/category\/cartography\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3563,"url":"https:\/\/rud.is\/b\/2015\/07\/26\/making-staticinteractive-voronoi-map-layers-in-ggplotleaflet\/","url_meta":{"origin":4061,"position":3},"title":"Making Static\/Interactive Voronoi Map Layers In ggplot\/leaflet","author":"hrbrmstr","date":"2015-07-26","format":false,"excerpt":"Despite having shown various ways to overcome D3 cartographic envy, there are always more examples that can cause the green monster to rear it's ugly head. Take the Voronoi Arc Map example. For those in need of a primer, a Voronoi tesslation\/diagram is: \u2026a partitioning of a plane into regions\u2026","rel":"","context":"In &quot;cartography&quot;","block_context":{"text":"cartography","link":"https:\/\/rud.is\/b\/category\/cartography\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":3649,"url":"https:\/\/rud.is\/b\/2015\/08\/27\/coloring-and-drawing-outside-the-lines-in-ggplot\/","url_meta":{"origin":4061,"position":4},"title":"Coloring (and Drawing) Outside the Lines in ggplot","author":"hrbrmstr","date":"2015-08-27","format":false,"excerpt":"Time for another Twitter-inspired blog post this week, this time from a tweet by @JonKalodimos: Is there a way to do this in #rstats #ggplot2 https:\/\/t.co\/kxWQFlYpbB\u2014 Jonathan Kalodimos (@JonKalodimos) August 27, 2015 I had seen and appreciated Ann's post on her makeover of the main graphic in [NPR's story](http:\/\/www.npr.org\/sections\/money\/2014\/10\/21\/357629765\/when-women-stopped-coding) and\u2026","rel":"","context":"In &quot;Data Visualization&quot;","block_context":{"text":"Data Visualization","link":"https:\/\/rud.is\/b\/category\/data-visualization\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":4449,"url":"https:\/\/rud.is\/b\/2016\/06\/16\/your-data-vis-spidey-sense-the-need-for-a-robust-utility-belt\/","url_meta":{"origin":4061,"position":5},"title":"Your data vis &#8220;Spidey-sense&#8221; &#038; the need for a robust &#8220;utility belt&#8221;","author":"hrbrmstr","date":"2016-06-16","format":false,"excerpt":"@theboysmithy did a [great piece](http:\/\/www.ft.com\/intl\/cms\/s\/0\/6f777c84-322b-11e6-ad39-3fee5ffe5b5b.html) on coming up with an alternate view for a timeline for an FT piece. Here's an excerpt (read the whole piece, though, it's worth it): Here is an example from a story recently featured in the FT: emerging- market populations are expected to age more\u2026","rel":"","context":"In &quot;d3&quot;","block_context":{"text":"d3","link":"https:\/\/rud.is\/b\/category\/d3\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/06\/RStudio.png?fit=1200%2C642&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/06\/RStudio.png?fit=1200%2C642&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/06\/RStudio.png?fit=1200%2C642&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/06\/RStudio.png?fit=1200%2C642&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2016\/06\/RStudio.png?fit=1200%2C642&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts\/4061","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/comments?post=4061"}],"version-history":[{"count":0,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts\/4061\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/media\/4078"}],"wp:attachment":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/media?parent=4061"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/categories?post=4061"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/tags?post=4061"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}