{"id":1290,"date":"2016-08-23T21:15:13","date_gmt":"2016-08-24T04:15:13","guid":{"rendered":"https:\/\/galencharlton.com\/blog\/?p=1290"},"modified":"2016-08-23T21:15:13","modified_gmt":"2016-08-24T04:15:13","slug":"visualizing-the-global-distribution-of-koha-installations-from-debian-packages","status":"publish","type":"post","link":"https:\/\/galencharlton.com\/blog\/2016\/08\/visualizing-the-global-distribution-of-koha-installations-from-debian-packages\/","title":{"rendered":"Visualizing the global distribution of Koha installations from Debian packages"},"content":{"rendered":"<p>A picture is worth\u00a0a thousand words:<\/p>\n<figure id=\"attachment_1291\" aria-describedby=\"caption-attachment-1291\" style=\"width: 625px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/galencharlton.com\/blog\/wp-content\/uploads\/2016\/08\/Koha_Debian_package_downloads.png\"><img loading=\"lazy\" class=\"wp-image-1291 size-large\" src=\"https:\/\/galencharlton.com\/blog\/wp-content\/uploads\/2016\/08\/Koha_Debian_package_downloads-1024x511.png\" alt=\"Downloads of Koha Debian packages in past 52 weeks\" width=\"625\" height=\"312\" srcset=\"https:\/\/galencharlton.com\/blog\/wp-content\/uploads\/2016\/08\/Koha_Debian_package_downloads-1024x511.png 1024w, https:\/\/galencharlton.com\/blog\/wp-content\/uploads\/2016\/08\/Koha_Debian_package_downloads-300x150.png 300w, https:\/\/galencharlton.com\/blog\/wp-content\/uploads\/2016\/08\/Koha_Debian_package_downloads-768x383.png 768w, https:\/\/galencharlton.com\/blog\/wp-content\/uploads\/2016\/08\/Koha_Debian_package_downloads-624x311.png 624w\" sizes=\"(max-width: 625px) 100vw, 625px\" \/><\/a><figcaption id=\"caption-attachment-1291\" class=\"wp-caption-text\">Click to get larger image.<\/figcaption><\/figure>\n<p>This represents the approximate geographic distribution of downloads of the Koha Debian packages over the past year. Data was taken from the Apache logs from debian.koha-community.org, which MPOW hosts. I counted only completed downloads of the koha-common package, of which there were over 25,000.<\/p>\n<p>Making the map turned out to be an opportunity for me to learn some Python. I first adapted a Python script I <a href=\"http:\/\/freegeoip.net\">found<\/a> on Stack Overflow to query <a href=\"https:\/\/freegeoip.net\/\">freegeoip.net<\/a>\u00a0and get the latitude and longitude\u00a0corresponding to each of the 9,432 distinct IP addresses that had downloaded the package.<\/p>\n<p>I then fed the results to <a href=\"http:\/\/www.openheatmap.com\/\">OpenHeatMap<\/a>. While that service is easy to use and is written\u00a0with GPL3 <a href=\"https:\/\/github.com\/petewarden\/openheatmap\">code<\/a>, I\u00a0didn&#8217;t quite like the fact that the result is delivered via\u00a0an Adobe Flash embed. \u00a0Consequently, I turned my attention to <a href=\"https:\/\/plot.ly\/\">Plotly<\/a>, and after some work, was able to write a Python script that does\u00a0the following:<\/p>\n<ol>\n<li>Fetch the CSV file containing the coordinates and number of downloads.<\/li>\n<li>Exclude as outliers rows where a given IP address made more than 100 downloads of the package during the past year \u2014 there were seven of these.<\/li>\n<li>Truncate the latitude and longitude to one decimal place \u2014 we need not <a href=\"http:\/\/fusion.net\/story\/290772\/ip-mapping-maxmind-new-us-default-location\/\">pester\u00a0corn farmers in Kansas for bugfixes<\/a>.<\/li>\n<li>Submit\u00a0the dataset to Plotly with which to generate a\u00a0bubble map.<\/li>\n<\/ol>\n<p>Here&#8217;s the code:<\/p>\n<pre class=\"lang:python decode:true\" title=\"Generate a Plotly bubble map\">#!\/usr\/bin\/python\r\n\r\n# adapted from example found at https:\/\/plot.ly\/python\/bubble-maps\/\r\n\r\nimport plotly.plotly as py\r\nimport pandas as pd\r\n\r\ndf = pd.read_csv('http:\/\/example.org\/koha-with-loc.csv')\r\ndf.head()\r\n\r\n# scale factor the size of the buble\r\nscale = 3\r\n\r\n# filter out rows where an IP address did more than\r\n# one hundred downloads\r\ndf = df[df['value'] &lt;= 100]\r\n\r\n# truncate latitude and longitude to one decimal\r\n# place\r\ndf['lat'] = df['lat'].map('{0:.1f}'.format)\r\ndf['lon'] = df['lon'].map('{0:.1f}'.format)\r\n\r\n# sum up the 'value' column as 'total_downloads'\r\naggregation = {\r\n    'value' : {\r\n        'total_downloads' : 'sum'\r\n    }\r\n}\r\n\r\n# create a DataFrame grouping by the truncated coordinates\r\ndf_sub = df.groupby(['lat', 'lon']).agg(aggregation).reset_index()\r\n\r\n\r\ncoords = []\r\npt = dict(\r\n    type = 'scattergeo',\r\n    lon = df_sub['lon'],\r\n    lat = df_sub['lat'],\r\n    text = 'Downloads: ' + df_sub['value']['total_downloads'],\r\n    marker = dict(\r\n        size = df_sub['value']['total_downloads'] * scale,\r\n        color = 'rgb(91,173,63)', # Koha green\r\n        line = dict(width=0.5, color='rgb(40,40,40)'),\r\n        sizemode = 'area'\r\n    ),\r\n    name = '')\r\ncoords.append(pt)\r\n\r\nlayout = dict(\r\n        title = 'Koha Debian package downloads',\r\n        showlegend = True,\r\n        geo = dict(\r\n            scope='world',\r\n            projection=dict( type='eckert4' ),\r\n            showland = True,\r\n            landcolor = 'rgb(217, 217, 217)',\r\n            subunitwidth=1,\r\n            countrywidth=1,\r\n            subunitcolor=\"rgb(255, 255, 255)\",\r\n            countrycolor=\"rgb(255, 255, 255)\"\r\n        ),\r\n    )\r\n\r\nfig = dict( data=coords, layout=layout )\r\npy.iplot( fig, validate=False, filename='koha-debian-downloads' )<\/pre>\n<p>An interactive version of the bubble map is also <a href=\"https:\/\/plot.ly\/~gmcharlt\/2\/koha-debian-package-downloads\/\">available<\/a>\u00a0on Plotly.<\/p>\n<div class=\"sharedaddy sd-sharing-enabled\"><div class=\"robots-nocontent sd-block sd-social sd-social-icon-text sd-sharing\"><h3 class=\"sd-title\">Share this:<\/h3><div class=\"sd-content\"><ul><li class=\"share-twitter\"><a rel=\"nofollow noopener noreferrer\" data-shared=\"sharing-twitter-1290\" class=\"share-twitter sd-button share-icon\" href=\"https:\/\/galencharlton.com\/blog\/2016\/08\/visualizing-the-global-distribution-of-koha-installations-from-debian-packages\/?share=twitter\" target=\"_blank\" title=\"Click to share on Twitter\"><span>Twitter<\/span><\/a><\/li><li><a href=\"#\" class=\"sharing-anchor sd-button share-more\"><span>More<\/span><\/a><\/li><li class=\"share-end\"><\/li><\/ul><div class=\"sharing-hidden\"><div class=\"inner\" style=\"display: none;\"><ul><li class=\"share-tumblr\"><a rel=\"nofollow noopener noreferrer\" data-shared=\"\" class=\"share-tumblr sd-button share-icon\" href=\"https:\/\/galencharlton.com\/blog\/2016\/08\/visualizing-the-global-distribution-of-koha-installations-from-debian-packages\/?share=tumblr\" target=\"_blank\" title=\"Click to share on Tumblr\"><span>Tumblr<\/span><\/a><\/li><li class=\"share-reddit\"><a rel=\"nofollow noopener noreferrer\" data-shared=\"\" class=\"share-reddit sd-button share-icon\" href=\"https:\/\/galencharlton.com\/blog\/2016\/08\/visualizing-the-global-distribution-of-koha-installations-from-debian-packages\/?share=reddit\" target=\"_blank\" title=\"Click to share on Reddit\"><span>Reddit<\/span><\/a><\/li><li class=\"share-end\"><\/li><li class=\"share-print\"><a rel=\"nofollow noopener noreferrer\" data-shared=\"\" class=\"share-print sd-button share-icon\" href=\"https:\/\/galencharlton.com\/blog\/2016\/08\/visualizing-the-global-distribution-of-koha-installations-from-debian-packages\/\" target=\"_blank\" title=\"Click to print\"><span>Print<\/span><\/a><\/li><li class=\"share-end\"><\/li><\/ul><\/div><\/div><\/div><\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>A picture is worth\u00a0a thousand words: This represents the approximate geographic distribution of downloads of the Koha Debian packages over the past year. Data was&#8230;<\/p>\n<div class=\"sharedaddy sd-sharing-enabled\"><div class=\"robots-nocontent sd-block sd-social sd-social-icon-text sd-sharing\"><h3 class=\"sd-title\">Share this:<\/h3><div class=\"sd-content\"><ul><li class=\"share-twitter\"><a rel=\"nofollow noopener noreferrer\" data-shared=\"sharing-twitter-1290\" class=\"share-twitter sd-button share-icon\" href=\"https:\/\/galencharlton.com\/blog\/2016\/08\/visualizing-the-global-distribution-of-koha-installations-from-debian-packages\/?share=twitter\" target=\"_blank\" title=\"Click to share on Twitter\"><span>Twitter<\/span><\/a><\/li><li><a href=\"#\" class=\"sharing-anchor sd-button share-more\"><span>More<\/span><\/a><\/li><li class=\"share-end\"><\/li><\/ul><div class=\"sharing-hidden\"><div class=\"inner\" style=\"display: none;\"><ul><li class=\"share-tumblr\"><a rel=\"nofollow noopener noreferrer\" data-shared=\"\" class=\"share-tumblr sd-button share-icon\" href=\"https:\/\/galencharlton.com\/blog\/2016\/08\/visualizing-the-global-distribution-of-koha-installations-from-debian-packages\/?share=tumblr\" target=\"_blank\" title=\"Click to share on Tumblr\"><span>Tumblr<\/span><\/a><\/li><li class=\"share-reddit\"><a rel=\"nofollow noopener noreferrer\" data-shared=\"\" class=\"share-reddit sd-button share-icon\" href=\"https:\/\/galencharlton.com\/blog\/2016\/08\/visualizing-the-global-distribution-of-koha-installations-from-debian-packages\/?share=reddit\" target=\"_blank\" title=\"Click to share on Reddit\"><span>Reddit<\/span><\/a><\/li><li class=\"share-end\"><\/li><li class=\"share-print\"><a rel=\"nofollow noopener noreferrer\" data-shared=\"\" class=\"share-print sd-button share-icon\" href=\"https:\/\/galencharlton.com\/blog\/2016\/08\/visualizing-the-global-distribution-of-koha-installations-from-debian-packages\/\" target=\"_blank\" title=\"Click to print\"><span>Print<\/span><\/a><\/li><li class=\"share-end\"><\/li><\/ul><\/div><\/div><\/div><\/div><\/div>","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"Visualizing the global distribution of Koha installations from Debian packages #kohails #code4lib","jetpack_is_tweetstorm":false},"categories":[4,10],"tags":[],"jetpack_featured_media_url":"","jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p3gJ9y-kO","_links":{"self":[{"href":"https:\/\/galencharlton.com\/blog\/wp-json\/wp\/v2\/posts\/1290"}],"collection":[{"href":"https:\/\/galencharlton.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/galencharlton.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/galencharlton.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/galencharlton.com\/blog\/wp-json\/wp\/v2\/comments?post=1290"}],"version-history":[{"count":5,"href":"https:\/\/galencharlton.com\/blog\/wp-json\/wp\/v2\/posts\/1290\/revisions"}],"predecessor-version":[{"id":1296,"href":"https:\/\/galencharlton.com\/blog\/wp-json\/wp\/v2\/posts\/1290\/revisions\/1296"}],"wp:attachment":[{"href":"https:\/\/galencharlton.com\/blog\/wp-json\/wp\/v2\/media?parent=1290"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/galencharlton.com\/blog\/wp-json\/wp\/v2\/categories?post=1290"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/galencharlton.com\/blog\/wp-json\/wp\/v2\/tags?post=1290"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}