├── 2020 ├── Code │ ├── 01_points │ │ ├── 01_points.R │ │ └── 01_points.png │ ├── 02_lines │ │ ├── 02_lines.R │ │ ├── 02_lines.pdf │ │ └── 02_lines.png │ ├── 03_Polygons │ │ ├── 03_polygons.R │ │ └── 03_polygons.png │ ├── 07_green │ │ ├── 07_green.R │ │ └── 07_green.png │ ├── 08_yellow │ │ ├── 08_yellow.R │ │ └── 08_yellow.png │ └── 20_population │ │ ├── 20_map-img.png │ │ ├── 20_map.gif │ │ └── population.R └── Data │ ├── 01_chipotle_stores.csv │ ├── 07_streetlight.csv │ ├── 20_Israel-pop.csv │ └── Israel-map │ ├── 00_Israel_0_sf.rds │ ├── gadm36_ISR_0_sf.rds │ ├── gadm36_ISR_0_sp.rds │ └── gadm36_ISR_1_sf.rds ├── 2021 ├── 01_points │ ├── 01_points.R │ └── trees.png ├── 02_lines │ ├── lines.R │ ├── lines.html │ ├── lines.png │ └── lines_files │ │ ├── Proj4Leaflet-1.0.1 │ │ └── proj4leaflet.js │ │ ├── htmlwidgets-1.5.4 │ │ └── htmlwidgets.js │ │ ├── jquery-1.12.4 │ │ └── jquery.min.js │ │ ├── leaflet-1.3.1 │ │ ├── images │ │ │ ├── layers-2x.png │ │ │ ├── layers.png │ │ │ ├── marker-icon-2x.png │ │ │ ├── marker-icon.png │ │ │ └── marker-shadow.png │ │ ├── leaflet.css │ │ └── leaflet.js │ │ ├── leaflet-binding-2.0.4.1 │ │ └── leaflet.js │ │ ├── leaflet-providers-1.9.0 │ │ └── leaflet-providers_1.9.0.js │ │ ├── leaflet-providers-plugin-2.0.4.1 │ │ └── leaflet-providers-plugin.js │ │ ├── leafletfix-1.0.0 │ │ └── leafletfix.css │ │ ├── proj4-2.6.2 │ │ └── proj4.min.js │ │ └── rstudio_leaflet-1.3.1 │ │ ├── images │ │ └── 1px.png │ │ └── rstudio_leaflet.css ├── 03_polygons │ ├── trains.R │ └── trains.png ├── 04_hexagons │ ├── busstops.R │ └── stops.png ├── 05_osm │ ├── street.png │ └── streets.R ├── 06_red │ ├── index.html │ ├── map-screenshot.png │ └── shelters.geojson ├── 07_green │ ├── bikelanes.R │ └── bikelanes.png ├── 08_blue │ ├── wave.R │ └── wave.png ├── 09_monochrome │ ├── israelbw.png │ └── monochrome.R ├── 10_raster │ ├── walk_from_dizengof.html │ ├── walk_from_dizengof_files │ │ ├── Proj4Leaflet-1.0.1 │ │ │ └── proj4leaflet.js │ │ ├── htmlwidgets-1.5.4 │ │ │ └── htmlwidgets.js │ │ ├── jquery-1.12.4 │ │ │ └── jquery.min.js │ │ ├── leaflet-1.3.1 │ │ │ ├── images │ │ │ │ ├── layers-2x.png │ │ │ │ ├── layers.png │ │ │ │ ├── marker-icon-2x.png │ │ │ │ ├── marker-icon.png │ │ │ │ └── marker-shadow.png │ │ │ ├── leaflet.css │ │ │ └── leaflet.js │ │ ├── leaflet-binding-2.0.4.1 │ │ │ └── leaflet.js │ │ ├── leafletfix-1.0.0 │ │ │ └── leafletfix.css │ │ ├── proj4-2.6.2 │ │ │ └── proj4.min.js │ │ └── rstudio_leaflet-1.3.1 │ │ │ ├── images │ │ │ └── 1px.png │ │ │ └── rstudio_leaflet.css │ ├── walking.R │ └── walking.png ├── 11_3d │ ├── 3d.R │ └── ramon.png ├── 13_natural-earth │ ├── visited.R │ └── visited.png ├── 17_land │ ├── land.R │ └── ta_area.png ├── 2021.Rproj ├── 20_movement │ ├── ice-cream.html │ ├── ice-cream_farthest.png │ ├── ice-cream_files │ │ ├── Proj4Leaflet-1.0.1 │ │ │ └── proj4leaflet.js │ │ ├── htmlwidgets-1.5.4 │ │ │ └── htmlwidgets.js │ │ ├── jquery-1.12.4 │ │ │ └── jquery.min.js │ │ ├── leaflet-1.3.1 │ │ │ ├── images │ │ │ │ ├── layers-2x.png │ │ │ │ ├── layers.png │ │ │ │ ├── marker-icon-2x.png │ │ │ │ ├── marker-icon.png │ │ │ │ └── marker-shadow.png │ │ │ ├── leaflet.css │ │ │ └── leaflet.js │ │ ├── leaflet-binding-2.0.4.1 │ │ │ └── leaflet.js │ │ ├── leaflet-providers-1.9.0 │ │ │ └── leaflet-providers_1.9.0.js │ │ ├── leaflet-providers-plugin-2.0.4.1 │ │ │ └── leaflet-providers-plugin.js │ │ ├── leafletfix-1.0.0 │ │ │ └── leafletfix.css │ │ ├── proj4-2.6.2 │ │ │ └── proj4.min.js │ │ └── rstudio_leaflet-1.3.1 │ │ │ ├── images │ │ │ └── 1px.png │ │ │ └── rstudio_leaflet.css │ ├── ice-cream_two_opt.png │ └── icecream.R ├── 22_borders │ ├── borders.R │ └── borders.png ├── 25_interactive │ ├── elderly.html │ ├── elderly.png │ ├── elderly_files │ │ ├── Proj4Leaflet-1.0.1 │ │ │ └── proj4leaflet.js │ │ ├── htmlwidgets-1.5.4 │ │ │ └── htmlwidgets.js │ │ ├── jquery-1.12.4 │ │ │ └── jquery.min.js │ │ ├── leaflet-1.3.1 │ │ │ ├── images │ │ │ │ ├── layers-2x.png │ │ │ │ ├── layers.png │ │ │ │ ├── marker-icon-2x.png │ │ │ │ ├── marker-icon.png │ │ │ │ └── marker-shadow.png │ │ │ ├── leaflet.css │ │ │ └── leaflet.js │ │ ├── leaflet-binding-2.0.4.1 │ │ │ └── leaflet.js │ │ ├── leaflet-providers-1.9.0 │ │ │ └── leaflet-providers_1.9.0.js │ │ ├── leaflet-providers-plugin-2.0.4.1 │ │ │ └── leaflet-providers-plugin.js │ │ ├── leafletfix-1.0.0 │ │ │ └── leafletfix.css │ │ ├── proj4-2.6.2 │ │ │ └── proj4.min.js │ │ └── rstudio_leaflet-1.3.1 │ │ │ ├── images │ │ │ └── 1px.png │ │ │ └── rstudio_leaflet.css │ └── src.R ├── data │ ├── Crime-map-2016_2021.xlsx │ ├── golda_locations.xlsx │ ├── ta-shapefile │ │ ├── gv_Tel_Aviv-Yafo_27.10.14.dbf │ │ ├── gv_Tel_Aviv-Yafo_27.10.14.jgw │ │ ├── gv_Tel_Aviv-Yafo_27.10.14.shp │ │ └── gv_Tel_Aviv-Yafo_27.10.14.shx │ ├── tatrees │ │ ├── %D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.cpg │ │ ├── %D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.dbf │ │ ├── %D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.prj │ │ ├── %D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.shp │ │ ├── %D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.shx │ │ ├── %D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.xml │ │ └── trees.csv │ └── wave │ │ ├── export.kml │ │ ├── export.xlsx │ │ ├── tsunami 5 meter line.cpg │ │ ├── tsunami 5 meter line.dbf │ │ ├── tsunami 5 meter line.prj │ │ ├── tsunami 5 meter line.shp │ │ └── tsunami 5 meter line.shx └── messing-around │ ├── ggmap.png │ ├── ggmap_polygon.png │ ├── ggmap_polygon_clean.png │ ├── israel.png │ ├── israelpre67.png │ ├── leaflet.png │ ├── leaflet_files │ ├── Proj4Leaflet-1.0.1 │ │ └── proj4leaflet.js │ ├── htmlwidgets-1.5.4 │ │ └── htmlwidgets.js │ ├── jquery-1.12.4 │ │ └── jquery.min.js │ ├── leaflet-1.3.1 │ │ ├── images │ │ │ ├── layers-2x.png │ │ │ ├── layers.png │ │ │ ├── marker-icon-2x.png │ │ │ ├── marker-icon.png │ │ │ └── marker-shadow.png │ │ ├── leaflet.css │ │ └── leaflet.js │ ├── leaflet-binding-2.0.4.1 │ │ └── leaflet.js │ ├── leafletfix-1.0.0 │ │ └── leafletfix.css │ ├── proj4-2.6.2 │ │ └── proj4.min.js │ └── rstudio_leaflet-1.3.1 │ │ ├── images │ │ └── 1px.png │ │ └── rstudio_leaflet.css │ ├── telaviv_tmap.png │ └── warmup.R ├── 2022 ├── 01_points │ ├── .ipynb_checkpoints │ │ ├── Polling address to Geolocation-checkpoint.ipynb │ │ └── polling_address_to_geo-checkpoint.ipynb │ ├── 01_points.R │ ├── 01_polling_locations.png │ ├── map.png │ ├── polling_address_to_geo.html │ ├── polling_address_to_geo.ipynb │ ├── polling_address_to_geo_files │ │ └── libs │ │ │ ├── bootstrap │ │ │ ├── bootstrap-icons.css │ │ │ ├── bootstrap-icons.woff │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.js │ │ │ ├── clipboard │ │ │ └── clipboard.min.js │ │ │ └── quarto-html │ │ │ ├── anchor.min.js │ │ │ ├── popper.min.js │ │ │ ├── quarto-syntax-highlighting.css │ │ │ ├── quarto.js │ │ │ ├── tippy.css │ │ │ └── tippy.umd.min.js │ ├── polling_station_rehovot.csv │ └── rehovot_polls.xlsx ├── 02_lines │ ├── lines.html │ ├── lines.png │ ├── lines_files │ │ ├── Proj4Leaflet-1.0.1 │ │ │ └── proj4leaflet.js │ │ ├── htmlwidgets-1.5.4 │ │ │ └── htmlwidgets.js │ │ ├── jquery-1.12.4 │ │ │ └── jquery.min.js │ │ ├── leaflet-1.3.1 │ │ │ ├── images │ │ │ │ ├── layers-2x.png │ │ │ │ ├── layers.png │ │ │ │ ├── marker-icon-2x.png │ │ │ │ ├── marker-icon.png │ │ │ │ └── marker-shadow.png │ │ │ ├── leaflet.css │ │ │ └── leaflet.js │ │ ├── leaflet-binding-2.1.1 │ │ │ └── leaflet.js │ │ ├── leaflet-providers-1.9.0 │ │ │ └── leaflet-providers_1.9.0.js │ │ ├── leaflet-providers-plugin-2.1.1 │ │ │ └── leaflet-providers-plugin.js │ │ ├── leafletfix-1.0.0 │ │ │ └── leafletfix.css │ │ ├── proj4-2.6.2 │ │ │ └── proj4.min.js │ │ └── rstudio_leaflet-1.3.1 │ │ │ ├── images │ │ │ └── 1px.png │ │ │ └── rstudio_leaflet.css │ └── routes.R ├── 03_polygons │ ├── 03_polygons.R │ ├── all_rides.rds │ ├── area_distribution.png │ ├── area_distribution_updated.png │ ├── bus_stops.png │ ├── bus_stops_updated.png │ └── stops_in_rehovot.rds ├── 07_raster │ ├── 07_raster.R │ ├── elevation.png │ └── elevation_high_res.png ├── 08_osm │ ├── .ipynb_checkpoints │ │ └── 08_osm-checkpoint.ipynb │ ├── 08_osm.ipynb │ ├── rehovot.png │ └── rehovot_sf │ │ ├── gv_Rehovot_2016_plt.dbf │ │ ├── gv_Rehovot_2016_plt.prj │ │ ├── gv_Rehovot_2016_plt.shp │ │ └── gv_Rehovot_2016_plt.shx └── 14_hexagons │ ├── 14_hexagons.R │ ├── 14_hexagons_accidents.R │ ├── accidents.png │ ├── biking.rds │ └── driving.rds ├── .gitignore ├── 30daymapchallenge.Rproj ├── README.md ├── data └── maps │ ├── 00_Israel_0_sf.rds │ ├── gadm36_ISR_0_sf.rds │ ├── gadm36_ISR_0_sp.rds │ ├── gadm36_ISR_1_sf.rds │ └── isr-full │ ├── israel_borders.dbf │ ├── israel_borders.prj │ ├── israel_borders.sbn │ ├── israel_borders.sbx │ ├── israel_borders.shp │ ├── israel_borders.shp.xml │ └── israel_borders.shx └── expc.csv /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | 6 | data/maps/judicial 7 | 8 | *.pptx -------------------------------------------------------------------------------- /2020/Code/01_points/01_points.R: -------------------------------------------------------------------------------- 1 | library(ggplot2) 2 | library(readr) 3 | library(maps) 4 | library(cowplot) 5 | library(ggforce) 6 | library(extrafont) 7 | library(emoGG) 8 | 9 | us_states <- map_data("state") 10 | dat <- read_csv("data/01_chipotle_stores.csv") 11 | 12 | # Highlight specific point 13 | point <- data.frame(lon = -77.1378, lat = 39.07526, label = "My most frequently visited location throughout my stay in the US", title = "865 Rockville Pike, Rockville, MD") 14 | 15 | ggplot(data = us_states, mapping = aes(x = long, y = lat, group = group))+ 16 | geom_polygon(fill = "grey85",color = "white", size = 0.5)+ 17 | geom_point(data = dat, aes(x = longitude, y = latitude, group = 1), color = "#451400", size = 0.3)+ 18 | coord_map(projection = 'albers', lat0 = 39, lat1 = 45)+ 19 | theme_map()+ 20 | labs(title = "Chipotle locations across the US", caption = "#30DayMapChallenge | Day: 01\nData: Kaggle | @Amit_Levinson")+ 21 | geom_mark_circle(data = point, mapping = aes(x = lon, y= lat, label = title, description = label, group = 1), radius = unit(0.01, "mm"), 22 | label.family = c("Segoe UI Black", "Segoe UI"), label.fontsize = c(10,9), label.colour = c("#451400", "#451400"), con.border = "none", 23 | con.colour = "grey55", expand = unit(0.01, "mm"), label.buffer = unit(30, "mm"), label.fill = "transparent", color = "white")+ 24 | geom_emoji(data = point, aes(x = lon, y = lat, group = 1), emoji = "1f4cd", size = 0.02)+ 25 | theme( 26 | plot.title = element_text(color = "#451400", hjust = 0.5, size = 24, family = "Segoe UI Black"), 27 | plot.caption = element_text(color = "#451400", hjust = 1, size = 8, family = "Segoe UI Light") 28 | ) 29 | 30 | ggsave("01_points/01_points.png", width = 10, height = 8) 31 | 32 | #Data set from: 33 | # https://www.kaggle.com/navneethc/chipotle -------------------------------------------------------------------------------- /2020/Code/01_points/01_points.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Code/01_points/01_points.png -------------------------------------------------------------------------------- /2020/Code/02_lines/02_lines.R: -------------------------------------------------------------------------------- 1 | library(tidyverse) 2 | library(osmdata) 3 | library(sf) 4 | library(extrafont) 5 | library(pdftools) 6 | 7 | # This gets us the long and lat min and max suitable for Tel-Aviv. 8 | # See link at the bottom of the script for a blog to create your own. 9 | tv_coordinates <- getbb("Tel Aviv Israel") 10 | 11 | # Start by getting the lines and point for the main streets 12 | streets <- tv_coordinates %>% 13 | opq() %>% 14 | add_osm_feature(key = "highway", 15 | value = c("motorway","primary", 16 | "secondary", "tertiary")) %>% 17 | osmdata_sf() 18 | 19 | small_streets <- tv_coordinates %>% 20 | opq() %>% 21 | add_osm_feature(key = "highway", 22 | value = c("residential", "living_street", 23 | "unclassified", "service", "footway")) %>% 24 | osmdata_sf() 25 | 26 | # PDF output -------------------------------------------------------------- 27 | 28 | # I deliberately add it to an object since the direct outputting is extremely slow. 29 | # I then render it to pdf and convert that to png which is much faster: 30 | plot_pdf <- ggplot()+ 31 | geom_sf(data = streets$osm_lines, 32 | inherit.aes = FALSE, 33 | color = "black", 34 | size = .6, 35 | alpha = .8)+ 36 | geom_sf(data = small_streets$osm_lines, 37 | inherit.aes = FALSE, 38 | color = "black", 39 | size = .4, 40 | alpha = .6)+ 41 | coord_sf(xlim = c(34.73900 , 34.85400), 42 | ylim = c(32.01650, 32.14750), 43 | expand = FALSE)+ 44 | theme_void()+ 45 | geom_text(aes(x= 34.80200, y = 32.02020, label = "Tel-Aviv, IL"), 46 | color = "grey15", family = "IBM Plex Sans Light", size = 14)+ 47 | labs(caption = "\n#30daymapchallenge | Day: 02\nData: OSM | @Amit_Levinson")+ 48 | theme( 49 | plot.caption = element_text(family = "IBM Plex Sans Light", size = 11, color = "gray25", face = "italic"), 50 | plot.caption.position = "plot", 51 | plot.margin = unit(c(2,4,2,2), "mm")) 52 | 53 | # Used pdf method from Cédric Scherer's tidytuesday outputs 54 | ggsave(plot = plot_pdf, filename = "Code/02_lines/02_lines2.pdf", width = 10, height = 18, device = cairo_pdf) 55 | 56 | pdf_convert(pdf = "Code/02_lines/02_lines.pdf", 57 | filenames = "Code/02_lines/02_lines.png", 58 | format = "png", dpi = 400) 59 | 60 | #Thanks to Chris' blog post on introducing us the plot: 61 | #https://ggplot2tutor.com/streetmaps/streetmaps/ -------------------------------------------------------------------------------- /2020/Code/02_lines/02_lines.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Code/02_lines/02_lines.pdf -------------------------------------------------------------------------------- /2020/Code/02_lines/02_lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Code/02_lines/02_lines.png -------------------------------------------------------------------------------- /2020/Code/03_Polygons/03_polygons.R: -------------------------------------------------------------------------------- 1 | library(ggplot2) 2 | library(dplyr) 3 | library(sf) 4 | library(ggrepel) 5 | library(jsonlite) 6 | library(httr) 7 | library(extrafont) 8 | library(ggtext) 9 | 10 | # Polygon data from https://gadm.org/download_country_v3.html 11 | shp <- readRDS("Data/00_Israel_0_sf.rds") 12 | 13 | # GET data from data.gov.il 14 | hotels <- GET("https://data.gov.il/api/3/action/datastore_search?resource_id=073b0370-dd72-4fbb-ab0e-bc2f8e85699f&limit=400") 15 | hotels <- fromJSON(rawToChar(hotels$content)) 16 | hotels <- hotels$result$records 17 | 18 | # Plot 19 | ggplot()+ 20 | geom_sf(data = shp, size = 1, color = "black", fill = "grey95")+ 21 | geom_point(data = hotels, aes(x = X, y = Y, label = Name), color = "#8A2BE2")+ 22 | theme_void()+ 23 | labs(title = "Hotels in Israel", subtitle = "Labeled hotels are over the the green line", 24 | caption = "#30DayMapChallenge | Day: 03\nData: data.gov.il | @Amit_Levinson")+ 25 | geom_text_repel(data = filter(hotels, Name %in% c("Kalya", "Almog")), mapping = aes(x = X, y= Y, label = Name), point.padding = 0.4 ,box.padding = 1, family = "IBM Plex Sans", color = "gray15", size = 3)+ 26 | xlim(c(34, 36.5))+ 27 | theme(text = element_text(family = "IBM Plex Sans"), 28 | plot.title = element_markdown(hjust = 0, size = 28, family = "IBM Plex Sans Medium"), 29 | plot.subtitle = element_text(size = 12), 30 | plot.caption = element_text(size = 8,family = "IBM Plex Sans Light", hjust = 0, color = "gray15"), 31 | plot.margin = unit(c(4,4,4,4), "mm")) 32 | 33 | ggsave(filename = "Code/03_polygons/03_polygons.png", height = 8, width = 6, dpi = 450) 34 | -------------------------------------------------------------------------------- /2020/Code/03_Polygons/03_polygons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Code/03_Polygons/03_polygons.png -------------------------------------------------------------------------------- /2020/Code/07_green/07_green.R: -------------------------------------------------------------------------------- 1 | library(readr) 2 | library(dplyr) 3 | library(ggplot2) 4 | library(osmdata) 5 | library(sf) 6 | library(pdftools) 7 | library(ggtext) 8 | library(extrafont) 9 | 10 | 11 | sf_trees <- read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-01-28/sf_trees.csv') 12 | 13 | # Get coordinates 14 | sf_coordinates <- getbb("San Francisco USA") 15 | 16 | # Get data from osm 17 | sf_roads_raw <- sf_coordinates %>% 18 | opq() %>% 19 | add_osm_feature("highway") %>% 20 | osmdata_sf() 21 | 22 | label_df <- data.frame( 23 | x = -122.44, 24 | y = 37.82, 25 | label = "**Trees** of San Francisco") 26 | 27 | plot_pdf <- ggplot()+ 28 | geom_sf(data = sf_roads_raw$osm_lines, 29 | color = "grey35", 30 | inherit.aes = FALSE, 31 | size = .6, 32 | alpha = .4)+ 33 | geom_point(data = sf_trees, aes(x = longitude, y = latitude), color = "#919c4c", size = 0.05)+ 34 | coord_sf(xlim = c(-122.51490, -122.35698), 35 | ylim = c(37.70809, 37.83240), 36 | expand = FALSE)+ 37 | geom_richtext(data = label_df,aes(x =x , y = y, label = label), inherit.aes = FALSE, fill = NA, label.color =NA, label.padding = unit(c(0,0,0,0), "pt"), size = 24, family = "Kaushan Script")+ 38 | geom_text(aes(x = -122.358, y = 37.711, label = "#30DayMapChallenge Day 07\nSource: DataSF | @Amit_Levinson"), size = 6, hjust = 1, family = "Kaushan Script", color = "grey25")+ 39 | theme_void()+ 40 | theme( 41 | panel.background = element_rect(fill = "#f8eed1"), 42 | panel.border = element_blank(), 43 | plot.title = element_markdown(size = 32), 44 | plot.margin = unit(c(4,4,4,4), "mm") 45 | ) 46 | 47 | # See Cédric Scherer on saving as pdf: 48 | # https://github.com/Z3tt/TidyTuesday/blob/master/R/2020_05_TreesSF.Rmd 49 | ggsave(plot = plot_pdf, filename = "Code/07_green/07_green.pdf", width = 19, height = 18.94, device = cairo_pdf) 50 | 51 | pdf_convert(pdf = "Code/07_green/07_green.pdf", 52 | filenames = "Code/07_green/07_green.png", 53 | format = "png") 54 | -------------------------------------------------------------------------------- /2020/Code/07_green/07_green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Code/07_green/07_green.png -------------------------------------------------------------------------------- /2020/Code/08_yellow/08_yellow.R: -------------------------------------------------------------------------------- 1 | library(snapbox) 2 | library(sf) 3 | library(ggplot2) 4 | library(readr) 5 | library(dplyr) 6 | library(extrafont) 7 | 8 | # List available shape files of Israel's municipality 9 | list.files("גבולות שיפוט", recursive = TRUE, pattern = "\\.shp$") 10 | # Read Be'er sheva 11 | b7 <- read_sf("גבולות שיפוט/���� ����/�� ����/����� ���� (Arc View)/gv_beer_sheva3.7.07.shp") 12 | 13 | 14 | # Read street light data 15 | # data from: https://www.beer-sheva.muni.il/OpenData/Pages/Data.aspx (seems to be broken now) 16 | b7_lights <- read_csv("Data/07_streetlight.csv") 17 | 18 | # Convert lights to sf and add title as a row 19 | b7_lights <- b7_lights %>% 20 | select(lat, lon) %>% 21 | mutate(label = "") %>% 22 | add_row(lat = 31.31, lon = 34.76, label = "Light posts in\nBe'er Sheva, IL") 23 | 24 | # Convert to sf 25 | lights_sf <- b7_lights %>% 26 | st_as_sf(coords = c("lon", "lat"), crs=4326) 27 | 28 | # Get boundaries of Be'er Sheva 29 | b7_area <- st_bbox(b7) 30 | 31 | # Retrieve mapbox, see link below for Jose Maria's code 32 | map_base <- ggplot()+ 33 | layer_mapbox(b7_area, 34 | mapbox_api_access_token = keyring::key_get("mapbox")) 35 | 36 | # Plot 37 | map_base + 38 | geom_sf(data = filter(lights_sf, label ==""), fill = NA, color = "#ffff00", size = 0.01, alpha = 0.6)+ 39 | geom_sf_text(data = lights_sf, aes(label = label),color = "#ffff00", size = 7, family = "Roboto Condensed", fontface = "italic")+ 40 | theme_void() 41 | 42 | # Save: 43 | ggsave("Code/08_yellow/08_yellow.png",width = 13.5,height = 17.5,units = c("cm"), dpi = 400,bg = "transparent") 44 | 45 | # Code I followed: 46 | # https://gist.github.com/JoseEchave/672df001307c7f4344418fc4edb999cc -------------------------------------------------------------------------------- /2020/Code/08_yellow/08_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Code/08_yellow/08_yellow.png -------------------------------------------------------------------------------- /2020/Code/20_population/20_map-img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Code/20_population/20_map-img.png -------------------------------------------------------------------------------- /2020/Code/20_population/20_map.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Code/20_population/20_map.gif -------------------------------------------------------------------------------- /2020/Code/20_population/population.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(sf) 3 | library(ggplot2) 4 | library(sp) 5 | library(cartogram) 6 | library(readr) 7 | library(gganimate) 8 | library(tweenr) 9 | library(broom) 10 | library(extrafont) 11 | 12 | # See R-graph gallery for original blog post on how to do it (minor change since to the {gganimate} API): 13 | # https://www.r-graph-gallery.com/a-smooth-transition-between-chloropleth-and-cartogram.html 14 | 15 | israel_sf <- readRDS("Data/Israel-map/gadm36_ISR_1_sf.Rds") 16 | 17 | # Convert Golan + North into one since we'll need it aligned with the population: 18 | israel_sf_joined <- israel_sf %>% 19 | mutate(group_agg = NAME_1, 20 | group_agg = case_when( 21 | group_agg %in% c("Golan", "HaZafon") ~ "North", 22 | group_agg == "HaDarom" ~ "South", 23 | group_agg == "HaMerkaz" ~ "Center", 24 | TRUE ~ NAME_1)) %>% 25 | group_by(group_agg) %>% 26 | summarise() 27 | 28 | # Alternatively, join using aggregate. Thanks to Michael Dorman for the help! 29 | # israel_sf_joined <- aggregate(israel_sf_joined["geometry"], st_drop_geometry(israel_sf_joined["group_agg"]), sum) 30 | 31 | # Israel population for 2017 from 32 | # https://data.gov.il/dataset/localauthorities2018 33 | pop <- read_csv("Data/20_Israel-pop.csv") 34 | 35 | 36 | pop_dat <- pop %>% 37 | group_by(district) %>% 38 | # Convert to by million 39 | summarise(pop_sum = sum(population_thousands)/ 1000) %>% 40 | # Change names to match the sf object 41 | mutate(name = case_when( 42 | district == "הדרום" ~ "South", 43 | district == "המרכז" ~ "Center", 44 | district == "הצפון" ~ "North", 45 | district == "חיפה" ~ "Haifa", 46 | district == "ירושלים" ~ "Jerusalem", 47 | district == "תל אביב" ~ "Tel Aviv" 48 | )) 49 | 50 | israel_sf_joined <- left_join(israel_sf_joined, pop_dat, by = c("group_agg" = "name")) %>% 51 | # For a cartogram transform coordinates 52 | st_transform(crs = 23038) 53 | 54 | # Make the cartogram 55 | cartogram <- cartogram_cont(israel_sf_joined, "pop_sum", itermax = 7) 56 | 57 | isr_carto <- as(st_geometry(cartogram), "Spatial") %>% 58 | tidy() 59 | 60 | israel <- as(st_geometry(israel_sf_joined), "Spatial") %>% 61 | tidy() 62 | 63 | isr_carto$id <- seq(1,nrow(isr_carto)) 64 | israel$id <- seq(1,nrow(israel)) 65 | 66 | israel_combined <- rbind(israel, isr_carto,israel) 67 | 68 | israel_combined$ease <- "cubic-in-out" 69 | israel_combined$time <- rep(c(1:3), each=nrow(israel)) 70 | 71 | israel_combined <- tween_elements(israel_combined, time='time', group='id', ease='ease', nframes = 40) 72 | 73 | # the geographical regions are saved as ID once we use the tween_elements. I imagine 74 | # you can solve this beforehand if you save the data as a dataframe in the spatial object 75 | israel_combined <- israel_combined %>% 76 | mutate(group = as.character(group), 77 | group = case_when( 78 | group == "ID1.1" ~ "Center", 79 | group == "ID2.1" ~ "Haifa", 80 | group == "ID3.1" ~ "Jerusalem", 81 | group == "ID4.1" ~ "North", 82 | group == "ID5.1" ~ "South", 83 | group == "ID6.1" ~ "Tel Aviv", 84 | TRUE ~ group 85 | )) 86 | 87 | israel_combined <- israel_combined %>% 88 | left_join(pop_dat, by = c("group" = "name")) 89 | 90 | # Start with exploring the plot on only 1 frame, adjust any aesthetics and 91 | # then explore with the animation 92 | p <- ggplot() + 93 | geom_polygon(data = israel_combined %>% arrange(order), aes(fill = pop_sum, x = long, y = lat, group = group) , size=0, alpha=0.9, color = "gray35") + 94 | scale_fill_continuous(trans = "reverse",name="Population (Millions)", guide = guide_legend(keyheight = unit(1, units = "mm"), keywidth=unit(6, units = "mm"), label.position = "bottom", title.position = 'top', ncol=1))+ 95 | labs(title = "Israel's population", subtitle = "Map transitions between a regular map to a cartogram, a map where\nthe geographic size is proportional to the population in that area.\nData is from Israel's CBS 2017 report and is aggregated at the district level", caption = "Data: data.gov.il\n@Amit_Levinson")+ 96 | theme_void() + 97 | theme(text = element_text(family = "IBM Plex Sans"), 98 | plot.margin = unit(c(3,3,3,5), "mm"), 99 | plot.title = element_text(size = 14, face = "bold"), 100 | plot.subtitle = element_text(size = 8, color = "gray15"), 101 | legend.title=element_text(size= 7), 102 | legend.text = element_text(size = 6), 103 | plot.caption = element_text(size = 6, face = "italic", color = "gray45"))+ 104 | transition_states(.frame)+ 105 | enter_fade() + 106 | exit_fade() 107 | 108 | # The rendering takes some time, so tweak and do any aesthetics on a filtered 109 | # version of the data. Just add %>% filter(.frame == 1) in the data argument above 110 | animate(p, start_pause = 3, width = 4, height = 7, units = "in", res = 150) 111 | 112 | anim_save("Code/20_population/20_map.gif") 113 | 114 | 115 | # Or make both plots just not animated ----------------------------------- 116 | 117 | library(patchwork) 118 | 119 | p1 <- ggplot() + 120 | geom_sf(data = israel_sf_joined, aes(fill = pop_sum) , size=0, alpha=0.9, color = "gray35") + 121 | scale_fill_gradient(trans = "reverse",name="Population (Millions)", guide = guide_legend(keyheight = unit(3, units = "mm"), keywidth=unit(8, units = "mm"), label.position = "bottom", title.position = 'top', nrow=1))+ 122 | labs(title = "Regular")+ 123 | theme_void() + 124 | theme(plot.title = element_text(size = 14), 125 | legend.title=element_text(size= 12), 126 | legend.text = element_text(size = 10), 127 | legend.spacing.x = unit(3, 'mm')) 128 | 129 | p2 <- ggplot() + 130 | geom_sf(data = cartogram, aes(fill = pop_sum) , size=0, alpha=0.9, color = "gray35") + 131 | scale_fill_continuous(trans = "reverse",name="Population (Millions)", guide = NULL)+ 132 | ggtitle("Cartogram")+ 133 | labs(title = "Cartogram", caption = "Data: data.gov.il\n@Amit_Levinson")+ 134 | theme_void() + 135 | theme(plot.title = element_text(size = 14), 136 | plot.caption = element_text(size = 10, face = "italic", color = "gray45")) 137 | 138 | # Stick plots together 139 | p <- p1+p2+ 140 | plot_layout(guides = 'collect')+ 141 | plot_annotation(title = "Israel's Population", subtitle = "A regular map and a cartogram, a map where the geographic size is proportional\nto the population in that area. Data is from Israel's CBS 2017 report and is\naggregated at the district level", 142 | theme = theme(plot.title = element_text(size = 18, face = "bold"), 143 | plot.subtitle = element_text(size = 14, color = "gray35"))) & 144 | theme(text = element_text('IBM Plex Sans'), 145 | plot.title = element_text(face = "bold"), 146 | legend.position = "bottom", 147 | plot.margin = unit(c(2,2,4,2), "mm")) 148 | 149 | ggsave("Code/20_population/20_map-img.png", p, height = 13, width = 8, units = "in", dpi = 300) -------------------------------------------------------------------------------- /2020/Data/20_Israel-pop.csv: -------------------------------------------------------------------------------- 1 | name,district,population_thousands 2 | אום אל-פחם,חיפה,54.2 3 | אופקים,הדרום,27.8 4 | אור יהודה,תל אביב,36.7 5 | אור עקיבא,חיפה,17.8 6 | אילת,הדרום,50.7 7 | אלעד,המרכז,46.9 8 | אריאל,אזור יהודה והשומרון,19.6 9 | אשדוד,הדרום,222.9 10 | אשקלון,הדרום,137.9 11 | באקה אל-גרביה,חיפה,29.0 12 | באר שבע,הדרום,207.6 13 | בית שאן,הצפון,17.7 14 | בית שמש,ירושלים,114.4 15 | ביתר עילית,אזור יהודה והשומרון,54.6 16 | בני ברק,תל אביב,193.8 17 | בת ים,תל אביב,128.7 18 | גבעת שמואל,המרכז,25.8 19 | גבעתיים,תל אביב,59.5 20 | דימונה,הדרום,33.7 21 | הוד השרון,המרכז,61.1 22 | הרצלייה,תל אביב,94.0 23 | חדרה,חיפה,94.0 24 | חולון,תל אביב,192.6 25 | חיפה,חיפה,281.1 26 | טבריה,הצפון,43.7 27 | טייבה,המרכז,42.4 28 | טירה,המרכז,25.7 29 | טירת כרמל,חיפה,21.3 30 | טמרה,הצפון,33.4 31 | יבנה,המרכז,45.5 32 | יהוד,המרכז,29.7 33 | יקנעם עילית,הצפון,22.7 34 | ירושלים,ירושלים,901.3 35 | כפר יונה,המרכז,22.5 36 | כפר סבא,המרכז,100.0 37 | כפר קאסם,המרכז,22.7 38 | כרמיאל,הצפון,45.9 39 | לוד,המרכז,74.6 40 | מגדל העמק,הצפון,25.4 41 | מודיעין עילית,אזור יהודה והשומרון,70.1 42 | מודיעין-מכבים-רעות*,המרכז,91.3 43 | מעלה אדומים,אזור יהודה והשומרון,37.8 44 | מעלות-תרשיחא,הצפון,21.3 45 | נהרייה,הצפון,56.1 46 | נס ציונה,המרכז,49.1 47 | נצרת,הצפון,76.6 48 | נצרת עילית,הצפון,40.6 49 | נשר,חיפה,23.7 50 | נתיבות,הדרום,33.8 51 | נתניה,המרכז,214.1 52 | סח'נין,הצפון,30.5 53 | עכו,הצפון,48.3 54 | עפולה,הצפון,49.2 55 | עראבה,הצפון,25.0 56 | ערד,הדרום,25.5 57 | פתח תקווה,המרכז,240.4 58 | צפת,הצפון,35.3 59 | קלנסווה,המרכז,22.4 60 | קריית אונו,תל אביב,39.4 61 | קריית אתא,חיפה,57.5 62 | קריית ביאליק,חיפה,39.6 63 | קריית גת,הדרום,53.5 64 | קריית ים,חיפה,39.7 65 | קריית מוצקין,חיפה,41.4 66 | קריית מלאכי,הדרום,22.3 67 | קריית שמונה,הצפון,22.8 68 | ראש העין,המרכז,50.5 69 | ראשון לציון,המרכז,249.9 70 | רהט,הדרום,66.8 71 | רחובות,המרכז,138.4 72 | רמלה,המרכז,75.7 73 | רמת גן,תל אביב,156.3 74 | רמת השרון,תל אביב,46.0 75 | רעננה,המרכז,72.8 76 | שדרות,הדרום,25.1 77 | שפרעם,הצפון,41.0 78 | תל אביב -יפו,תל אביב,443.9 79 | אבו גוש,ירושלים,7.3 80 | אבו סנאן,הצפון,13.7 81 | אבן יהודה,המרכז,13.7 82 | אורנית,אזור יהודה והשומרון,8.7 83 | אזור,תל אביב,12.7 84 | אכסאל,הצפון,14.2 85 | אליכין,המרכז,3.5 86 | אלפי מנשה,אזור יהודה והשומרון,7.8 87 | אלקנה,אזור יהודה והשומרון,3.9 88 | אעבלין,הצפון,13.0 89 | אפרת,אזור יהודה והשומרון,9.1 90 | באר יעקב,המרכז,22.9 91 | בועיינה-נוג'ידאת,הצפון,9.5 92 | בוקעאתא,הצפון,6.5 93 | ביר אל-מכסור,הצפון,9.1 94 | בית אל,אזור יהודה והשומרון,6.1 95 | בית אריה,אזור יהודה והשומרון,5.0 96 | בית ג'ן,הצפון,11.7 97 | בית דגן,המרכז,7.1 98 | "בני עי""ש",המרכז,7.0 99 | בנימינה-גבעת עדה*,חיפה,15.6 100 | "בסמ""ה",חיפה,9.5 101 | בסמת טבעון,הצפון,7.7 102 | בענה,הצפון,8.1 103 | גבעת זאב,אזור יהודה והשומרון,17.3 104 | ג'דיידה-מכר,הצפון,20.6 105 | גדרה,המרכז,27.5 106 | ג'ולס,הצפון,6.3 107 | ג'לג'וליה,המרכז,9.8 108 | גן יבנה,המרכז,23.5 109 | גני תקווה,המרכז,18.2 110 | ג'סר א-זרקא,חיפה,14.4 111 | ג'ש (גוש חלב),הצפון,3.1 112 | ג'ת,חיפה,11.6 113 | דאלית אל-כרמל,חיפה,17.2 114 | דבורייה,הצפון,10.2 115 | דייר אל-אסד,הצפון,12.1 116 | דייר חנא,הצפון,10.1 117 | הר אדר,אזור יהודה והשומרון,4.1 118 | זכרון יעקב,חיפה,23.0 119 | זמר,המרכז,6.8 120 | זרזיר,הצפון,7.8 121 | חורה,הדרום,20.8 122 | חורפיש,הצפון,6.2 123 | חצור הגלילית,הצפון,9.1 124 | חריש,חיפה,3.6 125 | טובא-זנגרייה,הצפון,6.5 126 | טורעאן,הצפון,13.7 127 | יאנוח-ג'ת,הצפון,6.5 128 | יבנאל,הצפון,4.3 129 | יסוד המעלה,הצפון,1.7 130 | יפיע,הצפון,18.7 131 | ירוחם,הדרום,9.5 132 | ירכא,הצפון,16.7 133 | כאבול,הצפון,13.6 134 | כאוכב אבו אל-היג'א,הצפון,3.5 135 | כוכב יאיר,המרכז,8.9 136 | כסיפה,הדרום,20.3 137 | כסרא-סמיע,הצפון,8.5 138 | כעביה-טבאש-חג'אג'רה,הצפון,5.2 139 | כפר ברא,המרכז,3.5 140 | כפר ורדים,הצפון,5.5 141 | כפר יאסיף,הצפון,9.9 142 | כפר כמא,הצפון,3.3 143 | כפר כנא,הצפון,22.0 144 | כפר מנדא,הצפון,19.3 145 | כפר קרע,חיפה,18.3 146 | כפר שמריהו,תל אביב,1.9 147 | כפר תבור,הצפון,4.1 148 | להבים,הדרום,6.4 149 | לקיה,הדרום,12.9 150 | מבשרת ציון,ירושלים,24.4 151 | מגאר,הצפון,22.3 152 | מג'ד אל-כרום,הצפון,15.1 153 | מגדל,הצפון,1.9 154 | מג'דל שמס,הצפון,10.9 155 | מזכרת בתיה,המרכז,14.2 156 | מזרעה,הצפון,3.8 157 | מטולה,הצפון,1.6 158 | מיתר,הדרום,7.7 159 | מסעדה,הצפון,3.6 160 | מעיליא,הצפון,3.2 161 | מעלה אפרים,אזור יהודה והשומרון,1.2 162 | מעלה עירון,חיפה,14.6 163 | מצפה רמון,הדרום,5.2 164 | משהד,הצפון,8.1 165 | נחף,הצפון,12.6 166 | סאג'ור,הצפון,4.1 167 | סביון*,המרכז,3.9 168 | ע'ג'ר,הצפון,2.6 169 | עומר,הדרום,7.6 170 | עיילבון,הצפון,5.6 171 | עילוט,הצפון,7.9 172 | עין מאהל,הצפון,12.8 173 | עין קנייא,הצפון,2.0 174 | עמנואל,אזור יהודה והשומרון,3.4 175 | עספיא,חיפה,12.1 176 | ערערה,חיפה,24.5 177 | ערערה-בנגב,הדרום,17.0 178 | פוריידיס,חיפה,12.9 179 | פסוטה,הצפון,3.1 180 | פקיעין (בוקייעה),הצפון,5.8 181 | פרדס חנה-כרכור,חיפה,41.1 182 | פרדסייה,המרכז,5.8 183 | קדומים,אזור יהודה והשומרון,4.5 184 | קדימה-צורן,המרכז,22.0 185 | קצרין,הצפון,7.1 186 | קריית ארבע,אזור יהודה והשומרון,7.3 187 | קריית טבעון,חיפה,17.7 188 | קריית יערים,ירושלים,4.8 189 | קריית עקרון,המרכז,10.9 190 | קרני שומרון,אזור יהודה והשומרון,7.4 191 | ראמה,הצפון,7.6 192 | ראש פינה,הצפון,3.1 193 | ריינה,הצפון,18.7 194 | רכסים,חיפה,11.8 195 | רמת ישי,הצפון,7.7 196 | שבלי - אום אל-גנם,הצפון,5.9 197 | שגב-שלום,הדרום,9.9 198 | שוהם,המרכז,20.9 199 | שלומי,הצפון,6.2 200 | שעב,הצפון,6.8 201 | תל מונד,המרכז,12.6 202 | תל שבע,הדרום,19.7 203 | אל קסום,הדרום,10.0 204 | אל-בטוף,הצפון,7.8 205 | אלונה,חיפה,2.3 206 | אשכול,הדרום,13.9 207 | באר טוביה,הדרום,23.1 208 | בוסתן אל-מרג',הצפון,7.7 209 | בני שמעון,הדרום,10.0 210 | ברנר,המרכז,7.9 211 | גדרות,המרכז,5.2 212 | גולן,הצפון,17.0 213 | גוש עציון,אזור יהודה והשומרון,23.5 214 | גזר,המרכז,26.5 215 | גן רווה,המרכז,6.1 216 | דרום השרון,המרכז,32.7 217 | הגלבוע,הצפון,29.9 218 | הגליל העליון,הצפון,17.8 219 | הגליל התחתון,הצפון,12.1 220 | הערבה התיכונה,הדרום,3.3 221 | הר חברון,אזור יהודה והשומרון,8.3 222 | זבולון,חיפה,13.4 223 | חבל אילות,הדרום,4.1 224 | חבל יבנה,המרכז,7.0 225 | חבל מודיעין,המרכז,23.4 226 | חוף אשקלון,הדרום,17.1 227 | חוף הכרמל,חיפה,30.8 228 | חוף השרון,המרכז,15.1 229 | יואב,הדרום,8.6 230 | לב השרון,המרכז,23.6 231 | לכיש,הדרום,11.4 232 | מבואות החרמון,הצפון,7.2 233 | מגידו,הצפון,11.6 234 | מגילות ים המלח,אזור יהודה והשומרון,1.6 235 | מטה אשר,הצפון,28.7 236 | מטה בנימין,אזור יהודה והשומרון,65.4 237 | מטה יהודה,ירושלים,56.6 238 | מנשה,חיפה,19.8 239 | מעלה יוסף,הצפון,10.5 240 | מרום הגליל,הצפון,15.4 241 | מרחבים,הדרום,13.7 242 | משגב,הצפון,28.0 243 | נווה מדבר,הדרום,9.1 244 | נחל שורק,המרכז,9.2 245 | עמק הירדן,הצפון,13.5 246 | עמק המעיינות,הצפון,13.1 247 | עמק חפר,המרכז,42.2 248 | עמק יזרעאל,הצפון,38.0 249 | עמק לוד,המרכז,15.0 250 | ערבות הירדן,אזור יהודה והשומרון,4.9 251 | רמת נגב,הדרום,7.6 252 | שדות נגב,הדרום,10.3 253 | שומרון,אזור יהודה והשומרון,41.1 254 | שער הנגב,הדרום,8.0 255 | שפיר,הדרום,11.0 256 | תמר,הדרום,1.5 257 | -------------------------------------------------------------------------------- /2020/Data/Israel-map/00_Israel_0_sf.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Data/Israel-map/00_Israel_0_sf.rds -------------------------------------------------------------------------------- /2020/Data/Israel-map/gadm36_ISR_0_sf.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Data/Israel-map/gadm36_ISR_0_sf.rds -------------------------------------------------------------------------------- /2020/Data/Israel-map/gadm36_ISR_0_sp.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Data/Israel-map/gadm36_ISR_0_sp.rds -------------------------------------------------------------------------------- /2020/Data/Israel-map/gadm36_ISR_1_sf.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2020/Data/Israel-map/gadm36_ISR_1_sf.rds -------------------------------------------------------------------------------- /2021/01_points/01_points.R: -------------------------------------------------------------------------------- 1 | library(sf) 2 | library(ggplot2) 3 | library(geojsonio) 4 | library(ggmap) 5 | library(dplyr) 6 | library(stringr) 7 | library(RColorBrewer) 8 | 9 | dat <- st_as_sf(geojson_read("https://opendata.arcgis.com/datasets/feec119124874c70994fa13a365bebf9_0.geojson", what = "sp")) 10 | 11 | Sys.setlocale("LC_ALL", "Hebrew") 12 | 13 | 14 | clean_data <- dat %>% 15 | mutate( 16 | # Extract years 17 | TreeEstimateAge = str_extract(TreeEstimateAge, "\\d+(-)?\\d*"), 18 | TreeEstimateAge = ifelse(TreeEstimateAge == "60-100", "60", TreeEstimateAge), 19 | TreeAge = factor(TreeEstimateAge, levels = c(NA, "10-20", "20-40", "40-60", "60", "100"), labels = c("10-20","20-40", "40-60", "60+", "100+")) 20 | ) 21 | 22 | telavivggmap <- get_googlemap(center = "tel aviv, israel", zoom = 13,style=c(feature="all",element="labels",visibility="off")) 23 | 24 | 25 | ggmap(telavivggmap)+ 26 | geom_sf(data = clean_data, aes(color = TreeAge), inherit.aes = FALSE, size = 1.5)+ 27 | scale_color_brewer(palette = "YlOrBr", na.value="grey", name = "Tree age (Years)")+ 28 | guides(color = guide_legend(nrow = 1, byrow = TRUE,override.aes = list(size=3)))+ 29 | labs(title = "Historical and preserved trees across Tel-Aviv", 30 | subtitle = "", 31 | caption = "Data: Israel's Ministry of Agriculture | Visualization: @Amit_Levinson")+ 32 | theme( 33 | text = element_text(family = "Segoe UI"), 34 | plot.title = element_text(size = 22, family = "Alegreya", hjust = 0.5, face = "bold"), 35 | plot.subtitle = element_text(size = 8), 36 | legend.position = "top", 37 | legend.direction = "horizontal", 38 | legend.key.size = unit(3,"mm"), 39 | legend.key.width = unit(5,"mm"), 40 | legend.title = element_text(size = 11, color = "gray10"), 41 | legend.text = element_text(size = 10, color = "gray25"), 42 | plot.caption = element_text(hjust = 0.5, color = "gray45", size = 10), 43 | plot.margin = margin(6,2,6,2,"mm"), 44 | panel.background = element_rect(fill = "white", color = NA), 45 | axis.text = element_blank(), 46 | axis.ticks = element_blank(), 47 | axis.title = element_blank(), 48 | legend.key=element_blank() 49 | ) 50 | 51 | ggsave("2021/01_points/trees.png",height = 8, width = 7, dpi = 500) 52 | -------------------------------------------------------------------------------- /2021/01_points/trees.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/01_points/trees.png -------------------------------------------------------------------------------- /2021/02_lines/lines.R: -------------------------------------------------------------------------------- 1 | 2 | # Code from Alexandra Kapp day 9: https://alexandrakapp.github.io/30daymapchallenge/index.html 3 | # Check it out^^ 4 | 5 | library(sf) 6 | library(dplyr) 7 | library(osrm) 8 | library(stplanr) 9 | library(leaflet) 10 | library(htmltools) 11 | library(htmlwidgets) 12 | library(webshot) 13 | 14 | # Get Tel Aviv shapefile to extract points for routes 15 | tel_aviv_file_name <- list.files(pattern =".Aviv.+\\.shp$", recursive = TRUE) 16 | tel_aviv_file <- read_sf(paste0(tel_aviv_file_name)) 17 | 18 | # Provide relevant crs to Tel-Aviv 19 | tel_aviv_file <- st_transform(st_set_crs(tel_aviv_file, 2039), 4326) 20 | 21 | routes <- route(from = st_coordinates(st_sample(tel_aviv_file, size = 1000)), 22 | to = st_coordinates(st_sample(tel_aviv_file, size = 1000)), 23 | route_fun = osrmRoute, 24 | returnclass = "sf") 25 | 26 | routes["count"] <- 1 27 | 28 | overlapping_segments <- overline(routes, attrib = "count") 29 | 30 | 31 | p <- leaflet(overlapping_segments) %>% 32 | addProviderTiles(providers$CartoDB.DarkMatter) %>% 33 | addPolylines(weight = overlapping_segments$count / 6, color = "white") %>% 34 | addControl(html = paste(tags$h1(HTML("Streets traveled
in Tel-Aviv"), style = "color:white; font-family:Merriweather; font-size: 28pt; padding-left: 12px; line-height: 1.2em;"), 35 | tags$div(HTML("Most commonly traveled streets
from a sample of 1000 routes."), style = "color:white; font-family:Segoe UI; font-size: 15pt; padding-left: 15px; margin-top:-20px")) 36 | , className = "fieldset { 37 | border: 0; 38 | }", position = "topleft") %>% 39 | addControl(html = tags$div(HTML("Adapted from Alexandra Kapp • Data: {stplanr} package • Amit Levinson"), style = "color:#BEBEBE; font-family:Segoe UI; font-size: 10pt; padding-left: 15px;"), className = "fieldset {border: 0;}", position = "bottomleft") 40 | 41 | # Saving a snapshot 42 | saveWidget(p, "2021/02_lines/lines.html") 43 | webshot("2021/02_lines/lines.html", file = "2021/02_lines/lines.png", zoom = 3, vwidth = 900, vheight = 700) 44 | -------------------------------------------------------------------------------- /2021/02_lines/lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/02_lines/lines.png -------------------------------------------------------------------------------- /2021/02_lines/lines_files/Proj4Leaflet-1.0.1/proj4leaflet.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | var L, proj4; 3 | if (typeof define === 'function' && define.amd) { 4 | // AMD 5 | define(['leaflet', 'proj4'], factory); 6 | } else if (typeof module === 'object' && typeof module.exports === "object") { 7 | // Node/CommonJS 8 | L = require('leaflet'); 9 | proj4 = require('proj4'); 10 | module.exports = factory(L, proj4); 11 | } else { 12 | // Browser globals 13 | if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined') 14 | throw 'Leaflet and proj4 must be loaded first'; 15 | factory(window.L, window.proj4); 16 | } 17 | }(function (L, proj4) { 18 | if (proj4.__esModule && proj4.default) { 19 | // If proj4 was bundled as an ES6 module, unwrap it to get 20 | // to the actual main proj4 object. 21 | // See discussion in https://github.com/kartena/Proj4Leaflet/pull/147 22 | proj4 = proj4.default; 23 | } 24 | 25 | L.Proj = {}; 26 | 27 | L.Proj._isProj4Obj = function(a) { 28 | return (typeof a.inverse !== 'undefined' && 29 | typeof a.forward !== 'undefined'); 30 | }; 31 | 32 | L.Proj.Projection = L.Class.extend({ 33 | initialize: function(code, def, bounds) { 34 | var isP4 = L.Proj._isProj4Obj(code); 35 | this._proj = isP4 ? code : this._projFromCodeDef(code, def); 36 | this.bounds = isP4 ? def : bounds; 37 | }, 38 | 39 | project: function (latlng) { 40 | var point = this._proj.forward([latlng.lng, latlng.lat]); 41 | return new L.Point(point[0], point[1]); 42 | }, 43 | 44 | unproject: function (point, unbounded) { 45 | var point2 = this._proj.inverse([point.x, point.y]); 46 | return new L.LatLng(point2[1], point2[0], unbounded); 47 | }, 48 | 49 | _projFromCodeDef: function(code, def) { 50 | if (def) { 51 | proj4.defs(code, def); 52 | } else if (proj4.defs[code] === undefined) { 53 | var urn = code.split(':'); 54 | if (urn.length > 3) { 55 | code = urn[urn.length - 3] + ':' + urn[urn.length - 1]; 56 | } 57 | if (proj4.defs[code] === undefined) { 58 | throw 'No projection definition for code ' + code; 59 | } 60 | } 61 | 62 | return proj4(code); 63 | } 64 | }); 65 | 66 | L.Proj.CRS = L.Class.extend({ 67 | includes: L.CRS, 68 | 69 | options: { 70 | transformation: new L.Transformation(1, 0, -1, 0) 71 | }, 72 | 73 | initialize: function(a, b, c) { 74 | var code, 75 | proj, 76 | def, 77 | options; 78 | 79 | if (L.Proj._isProj4Obj(a)) { 80 | proj = a; 81 | code = proj.srsCode; 82 | options = b || {}; 83 | 84 | this.projection = new L.Proj.Projection(proj, options.bounds); 85 | } else { 86 | code = a; 87 | def = b; 88 | options = c || {}; 89 | this.projection = new L.Proj.Projection(code, def, options.bounds); 90 | } 91 | 92 | L.Util.setOptions(this, options); 93 | this.code = code; 94 | this.transformation = this.options.transformation; 95 | 96 | if (this.options.origin) { 97 | this.transformation = 98 | new L.Transformation(1, -this.options.origin[0], 99 | -1, this.options.origin[1]); 100 | } 101 | 102 | if (this.options.scales) { 103 | this._scales = this.options.scales; 104 | } else if (this.options.resolutions) { 105 | this._scales = []; 106 | for (var i = this.options.resolutions.length - 1; i >= 0; i--) { 107 | if (this.options.resolutions[i]) { 108 | this._scales[i] = 1 / this.options.resolutions[i]; 109 | } 110 | } 111 | } 112 | 113 | this.infinite = !this.options.bounds; 114 | 115 | }, 116 | 117 | scale: function(zoom) { 118 | var iZoom = Math.floor(zoom), 119 | baseScale, 120 | nextScale, 121 | scaleDiff, 122 | zDiff; 123 | if (zoom === iZoom) { 124 | return this._scales[zoom]; 125 | } else { 126 | // Non-integer zoom, interpolate 127 | baseScale = this._scales[iZoom]; 128 | nextScale = this._scales[iZoom + 1]; 129 | scaleDiff = nextScale - baseScale; 130 | zDiff = (zoom - iZoom); 131 | return baseScale + scaleDiff * zDiff; 132 | } 133 | }, 134 | 135 | zoom: function(scale) { 136 | // Find closest number in this._scales, down 137 | var downScale = this._closestElement(this._scales, scale), 138 | downZoom = this._scales.indexOf(downScale), 139 | nextScale, 140 | nextZoom, 141 | scaleDiff; 142 | // Check if scale is downScale => return array index 143 | if (scale === downScale) { 144 | return downZoom; 145 | } 146 | if (downScale === undefined) { 147 | return -Infinity; 148 | } 149 | // Interpolate 150 | nextZoom = downZoom + 1; 151 | nextScale = this._scales[nextZoom]; 152 | if (nextScale === undefined) { 153 | return Infinity; 154 | } 155 | scaleDiff = nextScale - downScale; 156 | return (scale - downScale) / scaleDiff + downZoom; 157 | }, 158 | 159 | distance: L.CRS.Earth.distance, 160 | 161 | R: L.CRS.Earth.R, 162 | 163 | /* Get the closest lowest element in an array */ 164 | _closestElement: function(array, element) { 165 | var low; 166 | for (var i = array.length; i--;) { 167 | if (array[i] <= element && (low === undefined || low < array[i])) { 168 | low = array[i]; 169 | } 170 | } 171 | return low; 172 | } 173 | }); 174 | 175 | L.Proj.GeoJSON = L.GeoJSON.extend({ 176 | initialize: function(geojson, options) { 177 | this._callLevel = 0; 178 | L.GeoJSON.prototype.initialize.call(this, geojson, options); 179 | }, 180 | 181 | addData: function(geojson) { 182 | var crs; 183 | 184 | if (geojson) { 185 | if (geojson.crs && geojson.crs.type === 'name') { 186 | crs = new L.Proj.CRS(geojson.crs.properties.name); 187 | } else if (geojson.crs && geojson.crs.type) { 188 | crs = new L.Proj.CRS(geojson.crs.type + ':' + geojson.crs.properties.code); 189 | } 190 | 191 | if (crs !== undefined) { 192 | this.options.coordsToLatLng = function(coords) { 193 | var point = L.point(coords[0], coords[1]); 194 | return crs.projection.unproject(point); 195 | }; 196 | } 197 | } 198 | 199 | // Base class' addData might call us recursively, but 200 | // CRS shouldn't be cleared in that case, since CRS applies 201 | // to the whole GeoJSON, inluding sub-features. 202 | this._callLevel++; 203 | try { 204 | L.GeoJSON.prototype.addData.call(this, geojson); 205 | } finally { 206 | this._callLevel--; 207 | if (this._callLevel === 0) { 208 | delete this.options.coordsToLatLng; 209 | } 210 | } 211 | } 212 | }); 213 | 214 | L.Proj.geoJson = function(geojson, options) { 215 | return new L.Proj.GeoJSON(geojson, options); 216 | }; 217 | 218 | L.Proj.ImageOverlay = L.ImageOverlay.extend({ 219 | initialize: function (url, bounds, options) { 220 | L.ImageOverlay.prototype.initialize.call(this, url, null, options); 221 | this._projectedBounds = bounds; 222 | }, 223 | 224 | // Danger ahead: Overriding internal methods in Leaflet. 225 | // Decided to do this rather than making a copy of L.ImageOverlay 226 | // and doing very tiny modifications to it. 227 | // Future will tell if this was wise or not. 228 | _animateZoom: function (event) { 229 | var scale = this._map.getZoomScale(event.zoom); 230 | var northWest = L.point(this._projectedBounds.min.x, this._projectedBounds.max.y); 231 | var offset = this._projectedToNewLayerPoint(northWest, event.zoom, event.center); 232 | 233 | L.DomUtil.setTransform(this._image, offset, scale); 234 | }, 235 | 236 | _reset: function () { 237 | var zoom = this._map.getZoom(); 238 | var pixelOrigin = this._map.getPixelOrigin(); 239 | var bounds = L.bounds( 240 | this._transform(this._projectedBounds.min, zoom)._subtract(pixelOrigin), 241 | this._transform(this._projectedBounds.max, zoom)._subtract(pixelOrigin) 242 | ); 243 | var size = bounds.getSize(); 244 | 245 | L.DomUtil.setPosition(this._image, bounds.min); 246 | this._image.style.width = size.x + 'px'; 247 | this._image.style.height = size.y + 'px'; 248 | }, 249 | 250 | _projectedToNewLayerPoint: function (point, zoom, center) { 251 | var viewHalf = this._map.getSize()._divideBy(2); 252 | var newTopLeft = this._map.project(center, zoom)._subtract(viewHalf)._round(); 253 | var topLeft = newTopLeft.add(this._map._getMapPanePos()); 254 | 255 | return this._transform(point, zoom)._subtract(topLeft); 256 | }, 257 | 258 | _transform: function (point, zoom) { 259 | var crs = this._map.options.crs; 260 | var transformation = crs.transformation; 261 | var scale = crs.scale(zoom); 262 | 263 | return transformation.transform(point, scale); 264 | } 265 | }); 266 | 267 | L.Proj.imageOverlay = function (url, bounds, options) { 268 | return new L.Proj.ImageOverlay(url, bounds, options); 269 | }; 270 | 271 | return L.Proj; 272 | })); 273 | -------------------------------------------------------------------------------- /2021/02_lines/lines_files/leaflet-1.3.1/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/02_lines/lines_files/leaflet-1.3.1/images/layers-2x.png -------------------------------------------------------------------------------- /2021/02_lines/lines_files/leaflet-1.3.1/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/02_lines/lines_files/leaflet-1.3.1/images/layers.png -------------------------------------------------------------------------------- /2021/02_lines/lines_files/leaflet-1.3.1/images/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/02_lines/lines_files/leaflet-1.3.1/images/marker-icon-2x.png -------------------------------------------------------------------------------- /2021/02_lines/lines_files/leaflet-1.3.1/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/02_lines/lines_files/leaflet-1.3.1/images/marker-icon.png -------------------------------------------------------------------------------- /2021/02_lines/lines_files/leaflet-1.3.1/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/02_lines/lines_files/leaflet-1.3.1/images/marker-shadow.png -------------------------------------------------------------------------------- /2021/02_lines/lines_files/leaflet-providers-plugin-2.0.4.1/leaflet-providers-plugin.js: -------------------------------------------------------------------------------- 1 | LeafletWidget.methods.addProviderTiles = function(provider, layerId, group, options) { 2 | this.layerManager.addLayer(L.tileLayer.provider(provider, options), "tile", layerId, group); 3 | }; 4 | -------------------------------------------------------------------------------- /2021/02_lines/lines_files/leafletfix-1.0.0/leafletfix.css: -------------------------------------------------------------------------------- 1 | /* Work around CSS properties introduced on img by bootstrap */ 2 | img.leaflet-tile { 3 | padding: 0; 4 | margin: 0; 5 | border-radius: 0; 6 | border: none; 7 | } 8 | .info { 9 | padding: 6px 8px; 10 | font: 14px/16px Arial, Helvetica, sans-serif; 11 | background: white; 12 | background: rgba(255,255,255,0.8); 13 | box-shadow: 0 0 15px rgba(0,0,0,0.2); 14 | border-radius: 5px; 15 | } 16 | .legend { 17 | line-height: 18px; 18 | color: #555; 19 | } 20 | .legend svg text { 21 | fill: #555; 22 | } 23 | .legend svg line { 24 | stroke: #555; 25 | } 26 | .legend i { 27 | width: 18px; 28 | height: 18px; 29 | margin-right: 4px; 30 | opacity: 0.7; 31 | display: inline-block; 32 | vertical-align: top; 33 | /*For IE 7*/ 34 | zoom: 1; 35 | *display: inline; 36 | } 37 | -------------------------------------------------------------------------------- /2021/02_lines/lines_files/rstudio_leaflet-1.3.1/images/1px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/02_lines/lines_files/rstudio_leaflet-1.3.1/images/1px.png -------------------------------------------------------------------------------- /2021/02_lines/lines_files/rstudio_leaflet-1.3.1/rstudio_leaflet.css: -------------------------------------------------------------------------------- 1 | .leaflet-tooltip.leaflet-tooltip-text-only, 2 | .leaflet-tooltip.leaflet-tooltip-text-only:before, 3 | .leaflet-tooltip.leaflet-tooltip-text-only:after { 4 | background: none; 5 | border: none; 6 | box-shadow: none; 7 | } 8 | 9 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-left { 10 | margin-left: 5px; 11 | } 12 | 13 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-right { 14 | margin-left: -5px; 15 | } 16 | 17 | .leaflet-tooltip:after { 18 | border-right: 6px solid transparent; 19 | /* right: -16px; */ 20 | } 21 | 22 | .leaflet-popup-pane .leaflet-popup-tip-container { 23 | /* when the tooltip container is clicked, it is closed */ 24 | pointer-events: all; 25 | /* tooltips should display the "hand" icon, just like .leaflet-interactive*/ 26 | cursor: pointer; 27 | } 28 | 29 | /* have the widget be displayed in the right 'layer' */ 30 | .leaflet-map-pane { 31 | z-index: auto; 32 | } 33 | -------------------------------------------------------------------------------- /2021/03_polygons/trains.R: -------------------------------------------------------------------------------- 1 | library(sf) 2 | library(janitor) 3 | library(ggplot2) 4 | library(units) 5 | library(ggvoronoi) 6 | library(dplyr) 7 | library(ggtext) 8 | 9 | # Get Israel map, unnest to coordinates as polygons. 10 | isrfull <- read_sf("data/maps/isr-full/israel_borders.shp") 11 | isrfull <- st_transform(isrfull, 4326) 12 | isr_points <- as.data.frame(st_coordinates(isrfull)) 13 | 14 | # Similarly with the train station data 15 | dat <- read_sf("2021/data/rail_stat_onoff_month/RAIL_STAT_ONOFF_MONTH.shp") %>% 16 | clean_names() 17 | 18 | dat <- st_transform(dat, 4326) 19 | 20 | dat <- dat %>% 21 | st_coordinates(geometry) %>% 22 | as.data.frame() 23 | 24 | # Create Voronoi data 25 | isr_voronoi <- voronoi_polygon(data=dat, 26 | x="X",y="Y", 27 | outline=isr_points) 28 | 29 | # Converts output of voronoi_polygon to be plotted, but we'll move it to sfc_polygon for area calculation 30 | isr_voronoi <- fortify_voronoi(isr_voronoi) 31 | 32 | 33 | isr_voronoi_poloygon <- isr_voronoi %>% 34 | # Convert the coordinats of polygon to a sfc_polygon 35 | st_as_sf(coords = c("x", "y"), crs = 4326) %>% 36 | group_by(id) %>% 37 | # collect them together, keep only distinct point for train 38 | summarise(geometry = st_combine(geometry), 39 | train.y = max(point.x), 40 | train.x = max(point.x)) %>% 41 | st_cast("POLYGON") 42 | 43 | # Calculate area each train station comprises 44 | isr_voronoi_poloygon <- isr_voronoi_poloygon %>% 45 | st_transform(.,crs = 2039) %>% 46 | mutate(area = st_area(geometry), 47 | area = as.numeric(set_units(area, km^2))) %>% 48 | st_transform(crs = 4326) 49 | 50 | # Finally, plot 51 | ggplot(isr_voronoi_poloygon) + 52 | geom_sf(aes(fill = area), color = NA) + 53 | geom_point(data = dat, aes(x = X, y = Y), inherit.aes = FALSE, size = 0.05, alpha = 0.7)+ 54 | # Ignore the limits; played a little with adding white spice but removed for now 55 | coord_sf(xlim = c(min(isr_voronoi$x), max(isr_voronoi$x)))+ 56 | scale_fill_gradientn("Area (km2)", 57 | colors=viridis::plasma(10), trans = "log", breaks = c(10,100,1000,8000), labels = scales::comma)+ 58 | labs(title = "Nearest Train Station", 59 | subtitle = "The nearest train station for land areas in Israel.\nAll locations in an area are closer to that train\nstation (dot) than to any other", 60 | caption = "Data: Ministry of Transport | @Amit_Levinson")+ 61 | theme_minimal()+ 62 | theme( 63 | text = element_text(family = "Raleway"), 64 | plot.title = element_text(size = 18, "Playfair Display"), 65 | plot.title.position = "plot", 66 | plot.subtitle = element_text(size = 12), 67 | axis.text = element_blank(), 68 | axis.title = element_blank(), 69 | panel.grid = element_blank(), 70 | legend.title = element_markdown(size = 10), 71 | plot.caption = element_text(hjust = 0.5, size = 8, color = "gray15"), 72 | legend.text = element_text(size = 8), 73 | plot.margin = margin(6,2,6,2,"mm"), 74 | panel.background = element_rect(fill = "white", color = NA), 75 | plot.background = element_rect(fill = "white", color = NA) 76 | 77 | ) 78 | 79 | ggsave("2021/03_polygons/trains.png", width = 8, height = 7) 80 | -------------------------------------------------------------------------------- /2021/03_polygons/trains.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/03_polygons/trains.png -------------------------------------------------------------------------------- /2021/04_hexagons/busstops.R: -------------------------------------------------------------------------------- 1 | library(dplyr) 2 | library(sf) 3 | library(ggplot2) 4 | library(viridis) 5 | library(ggtext) 6 | library(data.table) 7 | 8 | # Get Israel map, unnest to coordinates as polygons. 9 | isrfull <- read_sf("data/maps/isr-full/israel_borders.shp") %>% 10 | st_transform(crs = 2039) 11 | 12 | # read data for Novemeber 3 13 | dat <- fread("https://openmobilitydata-data.s3-us-west-1.amazonaws.com/public/feeds/ministry-of-transport-and-road-safety/820/20211103/original/stops.txt") 14 | 15 | dat_clean <- dat %>% 16 | distinct(stop_lon, stop_lat, stop_id) 17 | 18 | # filter to dsitinct stop_id (which it should be) 19 | datsf <- dat_clean %>% 20 | select(stop_lon, stop_lat,stop_id, stop_id) %>% 21 | st_as_sf(coords = c("stop_lon", "stop_lat")) %>% 22 | st_set_crs(4326) %>% 23 | st_transform(crs = 2039) 24 | 25 | # Make grids 26 | isrfull_grid <- st_make_grid(isrfull, cellsize = 5000 , square = FALSE) 27 | # Get only intersecting grids 28 | grid_rds <- st_as_sf(st_intersection(isrfull_grid, isrfull)) 29 | 30 | # Add a unique id 31 | grid_rds <- st_as_sf(grid_rds) %>% 32 | mutate(id = 1:nrow(.)) 33 | 34 | 35 | # Join grid and stops 36 | gridpoint_joined <- st_join(grid_rds, datsf, left = TRUE) %>% 37 | mutate(stops = ifelse(is.na(stop_id), 0,1)) 38 | 39 | # for some reason I can't aggregate in the geometry object level, so use id instead: 40 | stops_per_grid <- gridpoint_joined %>% 41 | st_drop_geometry() %>% 42 | group_by(id) %>% 43 | summarise(stops = sum(stops)) %>% 44 | mutate(stops = na_if(stops, 0)) 45 | 46 | # Join back to grid object 47 | full_grid_stops <- grid_rds %>% 48 | left_join(stops_per_grid) %>% 49 | st_transform(crs = 4326) 50 | 51 | 52 | ggplot(full_grid_stops)+ 53 | geom_sf(aes(fill = stops), size = 0.1, color = "gray15")+ 54 | scale_fill_viridis(name = "Bus stops", trans = "log", breaks = c(1,10,100,500))+ 55 | labs(title = "Bus stops per 5km^2", 56 | caption = "Data: OpenMobilityData (11/3/2021) | Visualization: Amit_Levinson")+ 57 | coord_sf(xlim = c(33.5,36))+ 58 | 59 | theme( 60 | panel.background = element_rect(fill = "white", color = NA), 61 | plot.background = element_rect(fill = "white", color = NA), 62 | text = element_text(family = "Roboto"), 63 | plot.title = element_markdown(size = 18, "Merriweather", hjust = 1, face = "bold"), 64 | plot.title.position = "plot", 65 | plot.subtitle = element_text(size = 12), 66 | axis.text = element_blank(), 67 | axis.title = element_blank(), 68 | axis.ticks = element_blank(), 69 | panel.grid = element_blank(), 70 | legend.title = element_markdown(size = 10, color = "gray15", hjust = 0), 71 | plot.caption = element_text(hjust = 0.5, size = 8, color = "gray35"), 72 | legend.text = element_text(size = 8, hjust = 0, color = "gray15"), 73 | legend.position=c(0.3,0.75), 74 | legend.background = element_blank(), 75 | plot.margin = margin(6,2,6,2,"mm") 76 | ) 77 | 78 | ggsave("2021/04_hexagons/stops.png", width= 8, height= 7) 79 | -------------------------------------------------------------------------------- /2021/04_hexagons/stops.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/04_hexagons/stops.png -------------------------------------------------------------------------------- /2021/05_osm/street.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/05_osm/street.png -------------------------------------------------------------------------------- /2021/05_osm/streets.R: -------------------------------------------------------------------------------- 1 | library(osmdata) 2 | library(sf) 3 | library(dplyr) 4 | library(ggplot2) 5 | library(patchwork) 6 | junebug::font_hoist("Alegreya") # Hoist Alegreya to enjoy its various weights 7 | 8 | 9 | # Data collections & setup ------------------------------------------------ 10 | 11 | # Wrap the street collection info into a function: 12 | 13 | large_features <- c("motorway","primary","secondary", "tertiary") 14 | small_features <- c("residential", "living_street", "unclassified", "service", "footway") 15 | 16 | get_osm_data <- function (city, features) { 17 | getbb(city)%>% 18 | opq()%>% 19 | add_osm_feature(key = "highway", 20 | value = features) %>% 21 | osmdata_sf() 22 | 23 | } 24 | 25 | 26 | jlm_large <- get_osm_data("Jerusalem, IL", features = large_features) 27 | jlm_small <- get_osm_data("Jerusalem, IL", features = small_features) 28 | 29 | ny_large <- get_osm_data("Manhattan, NY", features = large_features) 30 | ny_small <- get_osm_data("Manhattan, NY", features = small_features) 31 | 32 | 33 | 34 | # Plot -------------------------------------------------------------------- 35 | 36 | theme_set(theme_void()) 37 | 38 | 39 | generate_plot <- function(large, small, title, glowsigma, glowexpand) { 40 | ggplot(data = small$osm_lines)+ 41 | geom_sf(color = "gray15", size = 0.2)+ 42 | with_outer_glow( 43 | geom_sf(data =large$osm_lines, inherit.aes = FALSE), 44 | colour = "yellow", 45 | sigma = glowsigma, 46 | expand = glowexpand 47 | )+ 48 | 49 | labs(title = title) + 50 | theme ( 51 | plot.title = element_text(size = 25, hjust = 0.5, family = "Alegreya Bold"), 52 | # For some reason I add this to solve FaceBook issues :( 53 | panel.background = element_rect(fill = "white", color = NA), 54 | plot.background = element_rect(fill = "white", color = NA) 55 | ) 56 | } 57 | 58 | 59 | # Combine ----------------------------------------------------------------- 60 | 61 | pny <- generate_plot(ny_large, ny_small, title = "Manhattan", glowsigma = 0.5, glowexpand = 1) 62 | pjlm <- generate_plot(jlm_large, jlm_small, title = "Jerusalem", glowsigma = 0.75, glowexpand = 1.5) 63 | 64 | combined <- pny + pjlm + 65 | plot_annotation( 66 | caption = "Data: OSM | Amit_Levinson", 67 | theme = theme( 68 | plot.caption = element_text(size = 11, family = "Alegreya", color = "gray25", hjust = 0), 69 | plot.margin = margin(4,0,4,0,"mm") 70 | )) 71 | 72 | ggsave("2021/05_osm/street.png" ,plot = combined, width = 13, height = 8) 73 | -------------------------------------------------------------------------------- /2021/06_red/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Document 6 | 7 | 8 | 9 | 13 | 14 | 15 |
16 | 17 | 43 | 44 | -------------------------------------------------------------------------------- /2021/06_red/map-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/06_red/map-screenshot.png -------------------------------------------------------------------------------- /2021/07_green/bikelanes.R: -------------------------------------------------------------------------------- 1 | library(sf) 2 | library(dplyr) 3 | library(ggplot2) 4 | 5 | # Get Tel Aviv shapefile to extract points for routes 6 | tel_aviv_file_name <- list.files(pattern =".Aviv.+\\.shp$", recursive = TRUE) 7 | tel_aviv_file <- read_sf(paste0(tel_aviv_file_name)) 8 | 9 | # Provide relevant crs to Tel-Aviv 10 | tel_aviv_file <- st_transform(st_set_crs(tel_aviv_file, 2039), 4326) 11 | 12 | biketrail <- read_sf("2021/data/biketrail/Bicycle Routes.shp") 13 | 14 | 15 | # Calculate length of routes ------------------------------------------------------------ 16 | 17 | trail_length <- st_transform(biketrail, 2039) 18 | 19 | trail_length %>% 20 | filter(!is.na(direction)) %>% 21 | st_length() %>% 22 | sum() 23 | 24 | # plot 25 | ggplot(tel_aviv_file)+ 26 | geom_sf(fill = "white", color = "black", size = 0.25)+ 27 | geom_sf(data = biketrail, inherit.aes = FALSE, color = '#50C878')+ 28 | theme_void()+ 29 | coord_sf()+ 30 | labs(title = "Bike Lanes in Tel-Aviv", 31 | caption = "Data: Tel-Aviv Open Data | Amit_Levinson")+ 32 | theme( 33 | text = element_text(family = 'Playfair Display'), 34 | plot.title = element_text(hjust = 0.5, family = 'Playfair Display', face="bold", size = 19), 35 | plot.caption = element_text(hjust = 0.5, size = 8, color = "gray20"), 36 | plot.background = element_rect(fill = '#E9E9E9', color = NA), 37 | panel.background = element_rect(fill = '#E9E9E9', color = NA), 38 | plot.margin = margin(4,2,2,4,"mm") 39 | ) 40 | 41 | ggsave("2021/07_green/bikelanes.png", width = 5, height = 6) 42 | -------------------------------------------------------------------------------- /2021/07_green/bikelanes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/07_green/bikelanes.png -------------------------------------------------------------------------------- /2021/08_blue/wave.R: -------------------------------------------------------------------------------- 1 | library(sf) 2 | library(ggmap) 3 | library(ggtext) 4 | 5 | tel_aviv_file_name <- list.files(pattern =".Aviv.+\\.shp$", recursive = TRUE) 6 | tel_aviv_file <- read_sf(paste0(tel_aviv_file_name)) 7 | 8 | # Provide relevant crs to Tel-Aviv 9 | tel_aviv_file <- st_transform(st_set_crs(tel_aviv_file, 2039), 4326) 10 | 11 | wave <- read_sf("2021/data/wave/tsunami 5 meter line.shp") %>% 12 | st_transform(., crs = 4326) %>% 13 | st_intersection(., tel_aviv_file) 14 | 15 | telavivggmap <- get_googlemap(center = "tel aviv, israel", zoom = 13,style=c(feature="all",element="labels",visibility="off")) 16 | 17 | ggmap(telavivggmap)+ 18 | geom_sf(data = wave, inherit.aes = FALSE, fill = NA, color = "#1f73b7", size =1.25)+ 19 | labs(title = "Area covered by a 5 meter tsunami wave in Tel-Aviv", 20 | caption = "Data: Tel-Aviv Open Data | Amit_Levinson")+ 21 | theme_void()+ 22 | theme( 23 | text = element_text(family = "Roboto Condensed"), 24 | plot.title = element_markdown(hjust = 0.5, size = 18, face = "bold"), 25 | panel.background = element_rect(fill = "white", color = NA), 26 | plot.background = element_rect(fill = "white", color = NA), 27 | plot.caption = element_text(size = 10, color = "gray15") 28 | ) 29 | 30 | ggsave("2021/08_blue/wave.png", width = 7, height = 8) 31 | 32 | -------------------------------------------------------------------------------- /2021/08_blue/wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/08_blue/wave.png -------------------------------------------------------------------------------- /2021/09_monochrome/israelbw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/09_monochrome/israelbw.png -------------------------------------------------------------------------------- /2021/09_monochrome/monochrome.R: -------------------------------------------------------------------------------- 1 | library(elevatr) 2 | library(rayshader) 3 | library(sf) 4 | 5 | # Get Israel map for extracting raster layer below, you can also use the {rgeoboundaries} instead 6 | # to get boundaries of a country you're interested in. 7 | isrfull <- read_sf("data/maps/isr-full/israel_borders.shp") 8 | isrfull <- st_transform(isrfull, 4326) 9 | 10 | # Get elevation data 11 | isrraster <- get_elev_raster(locations = isrfull, z = 9, clip = "locations") 12 | 13 | # Convert to matrix for rayshader plotting 14 | isrrayshader = raster_to_matrix(isrraster) 15 | 16 | isrrayshader %>% 17 | sphere_shade(texture = "bw") %>% 18 | plot_3d(isrrayshader, zscale = 10, fov = 0, theta = 0, zoom = 0.9, phi = 45, windowsize = c(1000, 800)) 19 | 20 | render_snapshot("2021/09_monochrome/israelbw", 21 | title_text = "Israel's\nElevation", 22 | title_offset = c(60,50), 23 | title_color = "black", 24 | title_size = 40, 25 | title_font = "PT Serif", 26 | vignette = 0.1) 27 | -------------------------------------------------------------------------------- /2021/10_raster/walk_from_dizengof_files/Proj4Leaflet-1.0.1/proj4leaflet.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | var L, proj4; 3 | if (typeof define === 'function' && define.amd) { 4 | // AMD 5 | define(['leaflet', 'proj4'], factory); 6 | } else if (typeof module === 'object' && typeof module.exports === "object") { 7 | // Node/CommonJS 8 | L = require('leaflet'); 9 | proj4 = require('proj4'); 10 | module.exports = factory(L, proj4); 11 | } else { 12 | // Browser globals 13 | if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined') 14 | throw 'Leaflet and proj4 must be loaded first'; 15 | factory(window.L, window.proj4); 16 | } 17 | }(function (L, proj4) { 18 | if (proj4.__esModule && proj4.default) { 19 | // If proj4 was bundled as an ES6 module, unwrap it to get 20 | // to the actual main proj4 object. 21 | // See discussion in https://github.com/kartena/Proj4Leaflet/pull/147 22 | proj4 = proj4.default; 23 | } 24 | 25 | L.Proj = {}; 26 | 27 | L.Proj._isProj4Obj = function(a) { 28 | return (typeof a.inverse !== 'undefined' && 29 | typeof a.forward !== 'undefined'); 30 | }; 31 | 32 | L.Proj.Projection = L.Class.extend({ 33 | initialize: function(code, def, bounds) { 34 | var isP4 = L.Proj._isProj4Obj(code); 35 | this._proj = isP4 ? code : this._projFromCodeDef(code, def); 36 | this.bounds = isP4 ? def : bounds; 37 | }, 38 | 39 | project: function (latlng) { 40 | var point = this._proj.forward([latlng.lng, latlng.lat]); 41 | return new L.Point(point[0], point[1]); 42 | }, 43 | 44 | unproject: function (point, unbounded) { 45 | var point2 = this._proj.inverse([point.x, point.y]); 46 | return new L.LatLng(point2[1], point2[0], unbounded); 47 | }, 48 | 49 | _projFromCodeDef: function(code, def) { 50 | if (def) { 51 | proj4.defs(code, def); 52 | } else if (proj4.defs[code] === undefined) { 53 | var urn = code.split(':'); 54 | if (urn.length > 3) { 55 | code = urn[urn.length - 3] + ':' + urn[urn.length - 1]; 56 | } 57 | if (proj4.defs[code] === undefined) { 58 | throw 'No projection definition for code ' + code; 59 | } 60 | } 61 | 62 | return proj4(code); 63 | } 64 | }); 65 | 66 | L.Proj.CRS = L.Class.extend({ 67 | includes: L.CRS, 68 | 69 | options: { 70 | transformation: new L.Transformation(1, 0, -1, 0) 71 | }, 72 | 73 | initialize: function(a, b, c) { 74 | var code, 75 | proj, 76 | def, 77 | options; 78 | 79 | if (L.Proj._isProj4Obj(a)) { 80 | proj = a; 81 | code = proj.srsCode; 82 | options = b || {}; 83 | 84 | this.projection = new L.Proj.Projection(proj, options.bounds); 85 | } else { 86 | code = a; 87 | def = b; 88 | options = c || {}; 89 | this.projection = new L.Proj.Projection(code, def, options.bounds); 90 | } 91 | 92 | L.Util.setOptions(this, options); 93 | this.code = code; 94 | this.transformation = this.options.transformation; 95 | 96 | if (this.options.origin) { 97 | this.transformation = 98 | new L.Transformation(1, -this.options.origin[0], 99 | -1, this.options.origin[1]); 100 | } 101 | 102 | if (this.options.scales) { 103 | this._scales = this.options.scales; 104 | } else if (this.options.resolutions) { 105 | this._scales = []; 106 | for (var i = this.options.resolutions.length - 1; i >= 0; i--) { 107 | if (this.options.resolutions[i]) { 108 | this._scales[i] = 1 / this.options.resolutions[i]; 109 | } 110 | } 111 | } 112 | 113 | this.infinite = !this.options.bounds; 114 | 115 | }, 116 | 117 | scale: function(zoom) { 118 | var iZoom = Math.floor(zoom), 119 | baseScale, 120 | nextScale, 121 | scaleDiff, 122 | zDiff; 123 | if (zoom === iZoom) { 124 | return this._scales[zoom]; 125 | } else { 126 | // Non-integer zoom, interpolate 127 | baseScale = this._scales[iZoom]; 128 | nextScale = this._scales[iZoom + 1]; 129 | scaleDiff = nextScale - baseScale; 130 | zDiff = (zoom - iZoom); 131 | return baseScale + scaleDiff * zDiff; 132 | } 133 | }, 134 | 135 | zoom: function(scale) { 136 | // Find closest number in this._scales, down 137 | var downScale = this._closestElement(this._scales, scale), 138 | downZoom = this._scales.indexOf(downScale), 139 | nextScale, 140 | nextZoom, 141 | scaleDiff; 142 | // Check if scale is downScale => return array index 143 | if (scale === downScale) { 144 | return downZoom; 145 | } 146 | if (downScale === undefined) { 147 | return -Infinity; 148 | } 149 | // Interpolate 150 | nextZoom = downZoom + 1; 151 | nextScale = this._scales[nextZoom]; 152 | if (nextScale === undefined) { 153 | return Infinity; 154 | } 155 | scaleDiff = nextScale - downScale; 156 | return (scale - downScale) / scaleDiff + downZoom; 157 | }, 158 | 159 | distance: L.CRS.Earth.distance, 160 | 161 | R: L.CRS.Earth.R, 162 | 163 | /* Get the closest lowest element in an array */ 164 | _closestElement: function(array, element) { 165 | var low; 166 | for (var i = array.length; i--;) { 167 | if (array[i] <= element && (low === undefined || low < array[i])) { 168 | low = array[i]; 169 | } 170 | } 171 | return low; 172 | } 173 | }); 174 | 175 | L.Proj.GeoJSON = L.GeoJSON.extend({ 176 | initialize: function(geojson, options) { 177 | this._callLevel = 0; 178 | L.GeoJSON.prototype.initialize.call(this, geojson, options); 179 | }, 180 | 181 | addData: function(geojson) { 182 | var crs; 183 | 184 | if (geojson) { 185 | if (geojson.crs && geojson.crs.type === 'name') { 186 | crs = new L.Proj.CRS(geojson.crs.properties.name); 187 | } else if (geojson.crs && geojson.crs.type) { 188 | crs = new L.Proj.CRS(geojson.crs.type + ':' + geojson.crs.properties.code); 189 | } 190 | 191 | if (crs !== undefined) { 192 | this.options.coordsToLatLng = function(coords) { 193 | var point = L.point(coords[0], coords[1]); 194 | return crs.projection.unproject(point); 195 | }; 196 | } 197 | } 198 | 199 | // Base class' addData might call us recursively, but 200 | // CRS shouldn't be cleared in that case, since CRS applies 201 | // to the whole GeoJSON, inluding sub-features. 202 | this._callLevel++; 203 | try { 204 | L.GeoJSON.prototype.addData.call(this, geojson); 205 | } finally { 206 | this._callLevel--; 207 | if (this._callLevel === 0) { 208 | delete this.options.coordsToLatLng; 209 | } 210 | } 211 | } 212 | }); 213 | 214 | L.Proj.geoJson = function(geojson, options) { 215 | return new L.Proj.GeoJSON(geojson, options); 216 | }; 217 | 218 | L.Proj.ImageOverlay = L.ImageOverlay.extend({ 219 | initialize: function (url, bounds, options) { 220 | L.ImageOverlay.prototype.initialize.call(this, url, null, options); 221 | this._projectedBounds = bounds; 222 | }, 223 | 224 | // Danger ahead: Overriding internal methods in Leaflet. 225 | // Decided to do this rather than making a copy of L.ImageOverlay 226 | // and doing very tiny modifications to it. 227 | // Future will tell if this was wise or not. 228 | _animateZoom: function (event) { 229 | var scale = this._map.getZoomScale(event.zoom); 230 | var northWest = L.point(this._projectedBounds.min.x, this._projectedBounds.max.y); 231 | var offset = this._projectedToNewLayerPoint(northWest, event.zoom, event.center); 232 | 233 | L.DomUtil.setTransform(this._image, offset, scale); 234 | }, 235 | 236 | _reset: function () { 237 | var zoom = this._map.getZoom(); 238 | var pixelOrigin = this._map.getPixelOrigin(); 239 | var bounds = L.bounds( 240 | this._transform(this._projectedBounds.min, zoom)._subtract(pixelOrigin), 241 | this._transform(this._projectedBounds.max, zoom)._subtract(pixelOrigin) 242 | ); 243 | var size = bounds.getSize(); 244 | 245 | L.DomUtil.setPosition(this._image, bounds.min); 246 | this._image.style.width = size.x + 'px'; 247 | this._image.style.height = size.y + 'px'; 248 | }, 249 | 250 | _projectedToNewLayerPoint: function (point, zoom, center) { 251 | var viewHalf = this._map.getSize()._divideBy(2); 252 | var newTopLeft = this._map.project(center, zoom)._subtract(viewHalf)._round(); 253 | var topLeft = newTopLeft.add(this._map._getMapPanePos()); 254 | 255 | return this._transform(point, zoom)._subtract(topLeft); 256 | }, 257 | 258 | _transform: function (point, zoom) { 259 | var crs = this._map.options.crs; 260 | var transformation = crs.transformation; 261 | var scale = crs.scale(zoom); 262 | 263 | return transformation.transform(point, scale); 264 | } 265 | }); 266 | 267 | L.Proj.imageOverlay = function (url, bounds, options) { 268 | return new L.Proj.ImageOverlay(url, bounds, options); 269 | }; 270 | 271 | return L.Proj; 272 | })); 273 | -------------------------------------------------------------------------------- /2021/10_raster/walk_from_dizengof_files/leaflet-1.3.1/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/10_raster/walk_from_dizengof_files/leaflet-1.3.1/images/layers-2x.png -------------------------------------------------------------------------------- /2021/10_raster/walk_from_dizengof_files/leaflet-1.3.1/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/10_raster/walk_from_dizengof_files/leaflet-1.3.1/images/layers.png -------------------------------------------------------------------------------- /2021/10_raster/walk_from_dizengof_files/leaflet-1.3.1/images/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/10_raster/walk_from_dizengof_files/leaflet-1.3.1/images/marker-icon-2x.png -------------------------------------------------------------------------------- /2021/10_raster/walk_from_dizengof_files/leaflet-1.3.1/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/10_raster/walk_from_dizengof_files/leaflet-1.3.1/images/marker-icon.png -------------------------------------------------------------------------------- /2021/10_raster/walk_from_dizengof_files/leaflet-1.3.1/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/10_raster/walk_from_dizengof_files/leaflet-1.3.1/images/marker-shadow.png -------------------------------------------------------------------------------- /2021/10_raster/walk_from_dizengof_files/leafletfix-1.0.0/leafletfix.css: -------------------------------------------------------------------------------- 1 | /* Work around CSS properties introduced on img by bootstrap */ 2 | img.leaflet-tile { 3 | padding: 0; 4 | margin: 0; 5 | border-radius: 0; 6 | border: none; 7 | } 8 | .info { 9 | padding: 6px 8px; 10 | font: 14px/16px Arial, Helvetica, sans-serif; 11 | background: white; 12 | background: rgba(255,255,255,0.8); 13 | box-shadow: 0 0 15px rgba(0,0,0,0.2); 14 | border-radius: 5px; 15 | } 16 | .legend { 17 | line-height: 18px; 18 | color: #555; 19 | } 20 | .legend svg text { 21 | fill: #555; 22 | } 23 | .legend svg line { 24 | stroke: #555; 25 | } 26 | .legend i { 27 | width: 18px; 28 | height: 18px; 29 | margin-right: 4px; 30 | opacity: 0.7; 31 | display: inline-block; 32 | vertical-align: top; 33 | /*For IE 7*/ 34 | zoom: 1; 35 | *display: inline; 36 | } 37 | -------------------------------------------------------------------------------- /2021/10_raster/walk_from_dizengof_files/rstudio_leaflet-1.3.1/images/1px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/10_raster/walk_from_dizengof_files/rstudio_leaflet-1.3.1/images/1px.png -------------------------------------------------------------------------------- /2021/10_raster/walk_from_dizengof_files/rstudio_leaflet-1.3.1/rstudio_leaflet.css: -------------------------------------------------------------------------------- 1 | .leaflet-tooltip.leaflet-tooltip-text-only, 2 | .leaflet-tooltip.leaflet-tooltip-text-only:before, 3 | .leaflet-tooltip.leaflet-tooltip-text-only:after { 4 | background: none; 5 | border: none; 6 | box-shadow: none; 7 | } 8 | 9 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-left { 10 | margin-left: 5px; 11 | } 12 | 13 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-right { 14 | margin-left: -5px; 15 | } 16 | 17 | .leaflet-tooltip:after { 18 | border-right: 6px solid transparent; 19 | /* right: -16px; */ 20 | } 21 | 22 | .leaflet-popup-pane .leaflet-popup-tip-container { 23 | /* when the tooltip container is clicked, it is closed */ 24 | pointer-events: all; 25 | /* tooltips should display the "hand" icon, just like .leaflet-interactive*/ 26 | cursor: pointer; 27 | } 28 | 29 | /* have the widget be displayed in the right 'layer' */ 30 | .leaflet-map-pane { 31 | z-index: auto; 32 | } 33 | -------------------------------------------------------------------------------- /2021/10_raster/walking.R: -------------------------------------------------------------------------------- 1 | library(stars) 2 | library(sf) 3 | library(htmltools) 4 | library(leaflet) 5 | library(raster) 6 | # remotes::install_github("GIScience/openrouteservice-r") 7 | library(openrouteservice) 8 | library(htmlwidgets) 9 | library(webshot) 10 | 11 | ta_iso <- ors_isochrones(locations = data.frame(x= 34.774225,y = 32.077915), 12 | profile = "foot-walking", 13 | range = 1800, 14 | interval = 300, 15 | output = "sf") 16 | 17 | ta_iso_min <- ta_iso %>% 18 | mutate(value = value / 60) 19 | 20 | 21 | # rasterize 22 | ta_raster <- raster(nrow = 270 , ncols = 450, ext = extent(ta_iso_min[,1:2])) 23 | ta_raster <- rasterize(ta_iso_min[,1:2], ta_raster, field = "value", fun = min) 24 | 25 | # Add crs to raster 26 | crs(ta_raster) <- CRS("+init=epsg:4326") 27 | 28 | bins <- seq(0,30,5) 29 | 30 | # Create color scale 31 | s <- colorRampPalette(c( "#FFFFCC", "#41B6C4")) 32 | palcolors <- s(6) 33 | 34 | pal <- colorBin(palcolors, domain = ta_raster, bins = seq(0,30,5), na.color = NA) 35 | 36 | 37 | p <- leaflet() %>% 38 | addTiles() %>% 39 | addRasterImage(ta_raster, colors = palcolors, opacity = 0.8) %>% 40 | addLegend(pal = pal, values = values(ta_raster), title = "Minutes walking", position = "bottomright", opacity = 0.8) %>% 41 | addControl(html = paste(tags$h1(HTML("Walking from
Dizengoff square"), style = "color:black; font-family:Merriweather; font-size: 26pt; padding-left: 8px; line-height: 1.2em;"), 42 | tags$div(HTML("How far can you reach when
walking away from Dizengoff
square, Tel-Aviv, IL."), style = "color:black; font-family:Segoe UI; font-size: 15pt; padding-left: 8px; margin-top:-20px")), className = "fieldset { 43 | border: 0; 44 | }", position = "topleft") %>% 45 | addControl(html = tags$div(HTML("Data: openrouteservice • Amit_Levinson"), style = "color:black; font-family:Segoe UI; font-size: 12pt; padding-left: 15px;"), className = "fieldset {border: 0;}", position = "bottomleft") 46 | 47 | # Save widget 48 | saveWidget(p, "2021/10_raster/walk_from_dizengof.html") 49 | # Save snapshot 50 | webshot("2021/10_raster/walk_from_dizengof.html", file = "2021/10_raster/walking.png", zoom = 3, vwidth = 900, vheight = 700) 51 | -------------------------------------------------------------------------------- /2021/10_raster/walking.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/10_raster/walking.png -------------------------------------------------------------------------------- /2021/11_3d/3d.R: -------------------------------------------------------------------------------- 1 | library(rayshader) 2 | library(rayvista) 3 | # devtools::install_github("h-a-graham/rayvista", dependencies=TRUE) 4 | library(rayrender) 5 | 6 | lat <- 30.609379 7 | long <- 34.884477 8 | 9 | 10 | ramon <- plot_3d_vista(lat = lat, long = long, radius= 9000, overlay_detail = 14, 11 | cache_dir = '2021/11_3d/cache',theta=25, phi=25, 12 | windowsize = 800) 13 | 14 | 15 | render_snapshot("2021/11_3d/ramon", 16 | title_text = "Ramon Crater", 17 | title_offset = c(60,50), 18 | title_color = "black", 19 | title_size = 40, 20 | title_font = "Playfair Display", 21 | vignette = 0.1, 22 | clear = TRUE) 23 | -------------------------------------------------------------------------------- /2021/11_3d/ramon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/11_3d/ramon.png -------------------------------------------------------------------------------- /2021/13_natural-earth/visited.R: -------------------------------------------------------------------------------- 1 | 2 | ## Code credited to gist from below and the d6berlin R package! 3 | ## Also thanks to Georgios for pointing it out @geokaramanis 4 | 5 | library(sf) 6 | library(rnaturalearth) 7 | library(ggplot2) 8 | library(dplyr) 9 | library(patchwork) 10 | 11 | # Process ----------------------------------------------------------------- 12 | 13 | ## code to preserve orthpgraphic view from this gist: 14 | ## https://gist.github.com/fzenoni/ef23faf6d1ada5e4a91c9ef23b0ba2c1 15 | ## via this issue: https://github.com/r-spatial/sf/issues/1050 16 | 17 | 18 | ## Load country data 19 | mini_world <- rnaturalearth::ne_countries(scale = "medium", returnclass = "sf") 20 | 21 | 22 | ## Define the orthographic projection ........................................ 23 | lat <- 20 24 | lon <- 40 25 | 26 | ortho <- paste0('+proj=ortho +lat_0=', lat, ' +lon_0=', lon, 27 | ' +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs') 28 | 29 | ## Define the polygon to split what lies within and without your projection .. 30 | circle <- 31 | suppressMessages( 32 | sf::st_point(x = c(0, 0)) %>% 33 | sf::st_buffer(dist = 6371000) %>% 34 | sf::st_sfc(crs = ortho) 35 | ) 36 | ## Project this polygon in lat-lon ........................................... 37 | circle_longlat <- 38 | circle %>% 39 | sf::st_transform(crs = 4326) 40 | 41 | ## You must decompose it into a string with ordered longitudes 42 | ## Then complete the polygon definition to cover the hemisphere .............. 43 | if(lat != 0) { 44 | circle_longlat <- sf::st_boundary(circle_longlat) 45 | 46 | circle_coords <- sf::st_coordinates(circle_longlat)[, c(1,2)] 47 | circle_coords <- circle_coords[order(circle_coords[, 1]),] 48 | circle_coords <- circle_coords[!duplicated(circle_coords),] 49 | 50 | ## Rebuild line ............................................................ 51 | circle_longlat <- 52 | sf::st_linestring(circle_coords) %>% 53 | sf::st_sfc(crs = 4326) 54 | 55 | if(lat > 0) { 56 | rectangle <- list(rbind(circle_coords, 57 | c(X = 180, circle_coords[nrow(circle_coords), 'Y']), 58 | c(X = 180, Y = 90), 59 | c(X = -180, Y = 90), 60 | c(X = -180, circle_coords[1, 'Y']), 61 | circle_coords[1, c('X','Y')])) %>% 62 | sf::st_polygon() %>% 63 | sf::st_sfc(crs = 4326) 64 | } else { 65 | rectangle <- list(rbind(circle_coords, 66 | c(X = 180, circle_coords[nrow(circle_coords), 'Y']), 67 | c(X = 180, Y = -90), 68 | c(X = -180, Y = -90), 69 | c(X = -180, circle_coords[1, 'Y']), 70 | circle_coords[1, c('X','Y')])) %>% 71 | sf::st_polygon() %>% 72 | sf::st_sfc(crs = 4326) 73 | } 74 | 75 | circle_longlat <- suppressMessages(sf::st_union( 76 | sf::st_make_valid(circle_longlat), 77 | sf::st_make_valid(rectangle)) 78 | ) 79 | } 80 | 81 | ## A small negative buffer is necessary to avoid polygons still disappearing 82 | ## in a few pathological cases ............................................... 83 | ## Comment Cédric: Doesn't work with -.09 anymore, returns empty object. 84 | ## But works also without the buffer, so using 0 here to 85 | ## return the same type of object. 86 | visible <- suppressMessages(suppressWarnings( 87 | sf::st_intersection(sf::st_make_valid(mini_world), 88 | sf::st_buffer(circle_longlat, 0)) %>% 89 | sf::st_transform(crs = ortho) 90 | )) 91 | 92 | ## Get reason why polygons are broken ........................................ 93 | broken_reason <- sf::st_is_valid(visible, reason = TRUE) 94 | 95 | ## First fix NA's by decomposing them ........................................ 96 | na_visible <- visible[is.na(broken_reason),] 97 | visible <- visible[!is.na(broken_reason),] 98 | 99 | ## Open and close polygons ................................................... 100 | na_visible <- sf::st_cast(na_visible, 'MULTILINESTRING') %>% 101 | sf::st_cast('LINESTRING', do_split=TRUE) 102 | na_visible <- na_visible %>% 103 | dplyr::mutate(npts = mapview::npts(geometry, by_feature = TRUE)) 104 | 105 | ## Exclude polygons with less than 4 points .................................. 106 | na_visible <- na_visible %>% 107 | dplyr::filter(npts >= 4) %>% 108 | dplyr::select(-npts) %>% 109 | sf::st_cast('POLYGON') 110 | 111 | ## Fix other broken polygons ................................................. 112 | broken <- which(!sf::st_is_valid(visible)) 113 | for(land in broken) { 114 | result = suppressWarnings(tryCatch({ 115 | visible[land,] <- 116 | sf::st_make_valid(visible[land,]) %>% 117 | sf::st_collection_extract() 118 | }, error = function(e) { 119 | visible[land,] <<- sf::st_buffer(visible[land,], 0) 120 | })) 121 | } 122 | 123 | ## Bind together the two tables .............................................. 124 | visible <- suppressMessages(rbind(visible, na_visible)) 125 | 126 | 127 | 128 | # ## Inset line ----------------------------------------------------------- 129 | 130 | 131 | israel_center <- filter(visible, name_long == "Israel") %>% 132 | st_centroid() %>% 133 | st_geometry() %>% 134 | st_coordinates() 135 | 136 | line_loc <- rbind(israel_center, israel_center + c(4e6, 4e6)) 137 | 138 | inset_line <- st_sfc(st_linestring(line_loc), crs = ortho) 139 | 140 | 141 | # # Create globe as ggplot .................................................... 142 | p_globe <- ggplot2::ggplot()+ 143 | ggplot2::geom_sf(data = circle, fill = "white") + 144 | ggplot2::geom_sf(data = circle, alpha = .5) + 145 | ggplot2::geom_sf(data = sf::st_collection_extract(visible), 146 | fill = "gray45", color = "gray55") + 147 | ggplot2::geom_sf(data = filter(visible, name_long == "Israel"), fill = "#4B0082", color = NA) + 148 | ggplot2::geom_sf(data = circle, color = "grey60", fill = NA, size = .5) + 149 | geom_sf(data = inset_line, color = "gray75", size = 0.3, linetype = "dashed")+ 150 | ggplot2::coord_sf(crs = ortho) + 151 | # labs( 152 | # title = "Countries I visited in the past two years" 153 | # ) + 154 | ggplot2::theme_void() + 155 | ggplot2::theme( 156 | panel.grid.major = element_blank() 157 | ) 158 | 159 | 160 | 161 | # Inset Israel ------------------------------------------------------------ 162 | 163 | circle <- st_point(x = c(35, 31)) %>% 164 | st_buffer(dist = 7) %>% 165 | st_sfc(crs = ortho) 166 | 167 | israel_zoomed <- st_intersection(circle, st_set_crs(mini_world, ortho)) 168 | 169 | p_small <- ggplot() + 170 | geom_sf(data = circle, color = "gray45",fill = "white")+ 171 | geom_sf(data = israel_zoomed, fill = "gray55")+ 172 | # Highlight Israel 173 | geom_sf(data = israel_zoomed[5], fill = "#4B0082", color = NA)+ 174 | coord_sf(xlim = c(27,43), ylim = c(22, 38))+ 175 | theme_void()+ 176 | theme( 177 | plot.background = element_rect(fill = "transparent", color = NA) 178 | ) 179 | 180 | 181 | p_globe + inset_element(p_small, left = 0.6, bottom = 0.7, right = 0.8, top = 1)+ 182 | plot_annotation( 183 | title = "Countries I visited in the past year", 184 | caption = "@Amit_Levinson", 185 | theme = theme( 186 | title = element_text(size = 16, family = "Playfair Display", face = "bold", hjust = 0), 187 | plot.caption = element_text(size = 8, family = "Playfair Display", color = "gray35", hjust = 0.5), 188 | plot.margin = margin(4,8,4,8,"mm") 189 | )) 190 | 191 | ggsave("2021/13_natural-earth/visited.png", width = 8, height = 8) 192 | 193 | -------------------------------------------------------------------------------- /2021/13_natural-earth/visited.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/13_natural-earth/visited.png -------------------------------------------------------------------------------- /2021/17_land/land.R: -------------------------------------------------------------------------------- 1 | library(ggplot2) 2 | library(sf) 3 | library(raster) 4 | library(dplyr) 5 | library(patchwork) 6 | 7 | tel_aviv_file_name <- list.files(path = "~/isr_maps", pattern =".Aviv.+\\.shp$", recursive = TRUE) 8 | # I use the file for different projects and reference it several times from a specific folder 9 | tel_aviv_file <- read_sf(paste0("C:/Users/amitl/R_code/isr_maps/", tel_aviv_file_name)) 10 | 11 | # Convert to raster 12 | r <- raster(tel_aviv_file,res =10) 13 | ras_ta <- rasterize(tel_aviv_file, r, field = 1) 14 | 15 | 16 | draw_plot <- function(ras_ta, direction) { 17 | 18 | 19 | # Turn raster object to data.frame 20 | ta_tiles <- ras_ta %>% 21 | as.data.frame(xy = TRUE) %>% 22 | filter(!is.na(layer)) %>% 23 | arrange({{direction}}) %>% 24 | # Split the raster object into deciles by id, giving us 10 equal sized groups of points. 25 | mutate(id = 1:nrow(.)) %>% 26 | mutate(point_to_labels = as.numeric(cut(id, breaks = quantile(id,probs = 0:10/10), labels = seq(10, 100, 10), include.lowest = TRUE)), 27 | # Not sure but we need to convert to numeric 28 | point_to_labels = point_to_labels * 10, 29 | # give a different color to each adjacent area 30 | fillcolor = ifelse( (point_to_labels / 10) %% 2 == 1, "#5E7893", "#2F4169")) 31 | 32 | p <- ggplot(ta_tiles)+ 33 | geom_sf(data = tel_aviv_file, inherit.aes = FALSE, fill = NA, color = 'gray55')+ 34 | geom_tile(aes(x = x,y = y,fill = fillcolor, color = fillcolor), size =.3, show.legend = FALSE, alpha = 0.3)+ 35 | theme_void()+ 36 | theme( 37 | panel.background = element_rect(fill = "white", color =NA) 38 | )+ 39 | scale_fill_identity() + 40 | scale_color_identity() 41 | 42 | return (p) 43 | 44 | } 45 | 46 | # vertical and horizontal map 47 | p_hor <- draw_plot(ras_ta, direction = y) 48 | p_ver <- draw_plot(ras_ta, direction = x) 49 | 50 | 51 | p_hor + p_ver+ 52 | plot_annotation( 53 | title = "Tel Aviv Split to Ten Equal Areas\n", 54 | caption = "@Amit_Levinson", 55 | theme = theme( 56 | text = element_text(family = "Lora"), 57 | plot.title = element_text(size = 24), 58 | plot.caption = element_text(size = 11, color = "gray25", hjust = 0.5), 59 | plot.margin = margin(5,3,5,3,"mm") 60 | )) 61 | 62 | ggsave("2021/17_land/ta_area.png", width= 13, height = 8) 63 | -------------------------------------------------------------------------------- /2021/17_land/ta_area.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/17_land/ta_area.png -------------------------------------------------------------------------------- /2021/2021.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_farthest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/20_movement/ice-cream_farthest.png -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_files/Proj4Leaflet-1.0.1/proj4leaflet.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | var L, proj4; 3 | if (typeof define === 'function' && define.amd) { 4 | // AMD 5 | define(['leaflet', 'proj4'], factory); 6 | } else if (typeof module === 'object' && typeof module.exports === "object") { 7 | // Node/CommonJS 8 | L = require('leaflet'); 9 | proj4 = require('proj4'); 10 | module.exports = factory(L, proj4); 11 | } else { 12 | // Browser globals 13 | if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined') 14 | throw 'Leaflet and proj4 must be loaded first'; 15 | factory(window.L, window.proj4); 16 | } 17 | }(function (L, proj4) { 18 | if (proj4.__esModule && proj4.default) { 19 | // If proj4 was bundled as an ES6 module, unwrap it to get 20 | // to the actual main proj4 object. 21 | // See discussion in https://github.com/kartena/Proj4Leaflet/pull/147 22 | proj4 = proj4.default; 23 | } 24 | 25 | L.Proj = {}; 26 | 27 | L.Proj._isProj4Obj = function(a) { 28 | return (typeof a.inverse !== 'undefined' && 29 | typeof a.forward !== 'undefined'); 30 | }; 31 | 32 | L.Proj.Projection = L.Class.extend({ 33 | initialize: function(code, def, bounds) { 34 | var isP4 = L.Proj._isProj4Obj(code); 35 | this._proj = isP4 ? code : this._projFromCodeDef(code, def); 36 | this.bounds = isP4 ? def : bounds; 37 | }, 38 | 39 | project: function (latlng) { 40 | var point = this._proj.forward([latlng.lng, latlng.lat]); 41 | return new L.Point(point[0], point[1]); 42 | }, 43 | 44 | unproject: function (point, unbounded) { 45 | var point2 = this._proj.inverse([point.x, point.y]); 46 | return new L.LatLng(point2[1], point2[0], unbounded); 47 | }, 48 | 49 | _projFromCodeDef: function(code, def) { 50 | if (def) { 51 | proj4.defs(code, def); 52 | } else if (proj4.defs[code] === undefined) { 53 | var urn = code.split(':'); 54 | if (urn.length > 3) { 55 | code = urn[urn.length - 3] + ':' + urn[urn.length - 1]; 56 | } 57 | if (proj4.defs[code] === undefined) { 58 | throw 'No projection definition for code ' + code; 59 | } 60 | } 61 | 62 | return proj4(code); 63 | } 64 | }); 65 | 66 | L.Proj.CRS = L.Class.extend({ 67 | includes: L.CRS, 68 | 69 | options: { 70 | transformation: new L.Transformation(1, 0, -1, 0) 71 | }, 72 | 73 | initialize: function(a, b, c) { 74 | var code, 75 | proj, 76 | def, 77 | options; 78 | 79 | if (L.Proj._isProj4Obj(a)) { 80 | proj = a; 81 | code = proj.srsCode; 82 | options = b || {}; 83 | 84 | this.projection = new L.Proj.Projection(proj, options.bounds); 85 | } else { 86 | code = a; 87 | def = b; 88 | options = c || {}; 89 | this.projection = new L.Proj.Projection(code, def, options.bounds); 90 | } 91 | 92 | L.Util.setOptions(this, options); 93 | this.code = code; 94 | this.transformation = this.options.transformation; 95 | 96 | if (this.options.origin) { 97 | this.transformation = 98 | new L.Transformation(1, -this.options.origin[0], 99 | -1, this.options.origin[1]); 100 | } 101 | 102 | if (this.options.scales) { 103 | this._scales = this.options.scales; 104 | } else if (this.options.resolutions) { 105 | this._scales = []; 106 | for (var i = this.options.resolutions.length - 1; i >= 0; i--) { 107 | if (this.options.resolutions[i]) { 108 | this._scales[i] = 1 / this.options.resolutions[i]; 109 | } 110 | } 111 | } 112 | 113 | this.infinite = !this.options.bounds; 114 | 115 | }, 116 | 117 | scale: function(zoom) { 118 | var iZoom = Math.floor(zoom), 119 | baseScale, 120 | nextScale, 121 | scaleDiff, 122 | zDiff; 123 | if (zoom === iZoom) { 124 | return this._scales[zoom]; 125 | } else { 126 | // Non-integer zoom, interpolate 127 | baseScale = this._scales[iZoom]; 128 | nextScale = this._scales[iZoom + 1]; 129 | scaleDiff = nextScale - baseScale; 130 | zDiff = (zoom - iZoom); 131 | return baseScale + scaleDiff * zDiff; 132 | } 133 | }, 134 | 135 | zoom: function(scale) { 136 | // Find closest number in this._scales, down 137 | var downScale = this._closestElement(this._scales, scale), 138 | downZoom = this._scales.indexOf(downScale), 139 | nextScale, 140 | nextZoom, 141 | scaleDiff; 142 | // Check if scale is downScale => return array index 143 | if (scale === downScale) { 144 | return downZoom; 145 | } 146 | if (downScale === undefined) { 147 | return -Infinity; 148 | } 149 | // Interpolate 150 | nextZoom = downZoom + 1; 151 | nextScale = this._scales[nextZoom]; 152 | if (nextScale === undefined) { 153 | return Infinity; 154 | } 155 | scaleDiff = nextScale - downScale; 156 | return (scale - downScale) / scaleDiff + downZoom; 157 | }, 158 | 159 | distance: L.CRS.Earth.distance, 160 | 161 | R: L.CRS.Earth.R, 162 | 163 | /* Get the closest lowest element in an array */ 164 | _closestElement: function(array, element) { 165 | var low; 166 | for (var i = array.length; i--;) { 167 | if (array[i] <= element && (low === undefined || low < array[i])) { 168 | low = array[i]; 169 | } 170 | } 171 | return low; 172 | } 173 | }); 174 | 175 | L.Proj.GeoJSON = L.GeoJSON.extend({ 176 | initialize: function(geojson, options) { 177 | this._callLevel = 0; 178 | L.GeoJSON.prototype.initialize.call(this, geojson, options); 179 | }, 180 | 181 | addData: function(geojson) { 182 | var crs; 183 | 184 | if (geojson) { 185 | if (geojson.crs && geojson.crs.type === 'name') { 186 | crs = new L.Proj.CRS(geojson.crs.properties.name); 187 | } else if (geojson.crs && geojson.crs.type) { 188 | crs = new L.Proj.CRS(geojson.crs.type + ':' + geojson.crs.properties.code); 189 | } 190 | 191 | if (crs !== undefined) { 192 | this.options.coordsToLatLng = function(coords) { 193 | var point = L.point(coords[0], coords[1]); 194 | return crs.projection.unproject(point); 195 | }; 196 | } 197 | } 198 | 199 | // Base class' addData might call us recursively, but 200 | // CRS shouldn't be cleared in that case, since CRS applies 201 | // to the whole GeoJSON, inluding sub-features. 202 | this._callLevel++; 203 | try { 204 | L.GeoJSON.prototype.addData.call(this, geojson); 205 | } finally { 206 | this._callLevel--; 207 | if (this._callLevel === 0) { 208 | delete this.options.coordsToLatLng; 209 | } 210 | } 211 | } 212 | }); 213 | 214 | L.Proj.geoJson = function(geojson, options) { 215 | return new L.Proj.GeoJSON(geojson, options); 216 | }; 217 | 218 | L.Proj.ImageOverlay = L.ImageOverlay.extend({ 219 | initialize: function (url, bounds, options) { 220 | L.ImageOverlay.prototype.initialize.call(this, url, null, options); 221 | this._projectedBounds = bounds; 222 | }, 223 | 224 | // Danger ahead: Overriding internal methods in Leaflet. 225 | // Decided to do this rather than making a copy of L.ImageOverlay 226 | // and doing very tiny modifications to it. 227 | // Future will tell if this was wise or not. 228 | _animateZoom: function (event) { 229 | var scale = this._map.getZoomScale(event.zoom); 230 | var northWest = L.point(this._projectedBounds.min.x, this._projectedBounds.max.y); 231 | var offset = this._projectedToNewLayerPoint(northWest, event.zoom, event.center); 232 | 233 | L.DomUtil.setTransform(this._image, offset, scale); 234 | }, 235 | 236 | _reset: function () { 237 | var zoom = this._map.getZoom(); 238 | var pixelOrigin = this._map.getPixelOrigin(); 239 | var bounds = L.bounds( 240 | this._transform(this._projectedBounds.min, zoom)._subtract(pixelOrigin), 241 | this._transform(this._projectedBounds.max, zoom)._subtract(pixelOrigin) 242 | ); 243 | var size = bounds.getSize(); 244 | 245 | L.DomUtil.setPosition(this._image, bounds.min); 246 | this._image.style.width = size.x + 'px'; 247 | this._image.style.height = size.y + 'px'; 248 | }, 249 | 250 | _projectedToNewLayerPoint: function (point, zoom, center) { 251 | var viewHalf = this._map.getSize()._divideBy(2); 252 | var newTopLeft = this._map.project(center, zoom)._subtract(viewHalf)._round(); 253 | var topLeft = newTopLeft.add(this._map._getMapPanePos()); 254 | 255 | return this._transform(point, zoom)._subtract(topLeft); 256 | }, 257 | 258 | _transform: function (point, zoom) { 259 | var crs = this._map.options.crs; 260 | var transformation = crs.transformation; 261 | var scale = crs.scale(zoom); 262 | 263 | return transformation.transform(point, scale); 264 | } 265 | }); 266 | 267 | L.Proj.imageOverlay = function (url, bounds, options) { 268 | return new L.Proj.ImageOverlay(url, bounds, options); 269 | }; 270 | 271 | return L.Proj; 272 | })); 273 | -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_files/leaflet-1.3.1/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/20_movement/ice-cream_files/leaflet-1.3.1/images/layers-2x.png -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_files/leaflet-1.3.1/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/20_movement/ice-cream_files/leaflet-1.3.1/images/layers.png -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_files/leaflet-1.3.1/images/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/20_movement/ice-cream_files/leaflet-1.3.1/images/marker-icon-2x.png -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_files/leaflet-1.3.1/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/20_movement/ice-cream_files/leaflet-1.3.1/images/marker-icon.png -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_files/leaflet-1.3.1/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/20_movement/ice-cream_files/leaflet-1.3.1/images/marker-shadow.png -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_files/leaflet-providers-plugin-2.0.4.1/leaflet-providers-plugin.js: -------------------------------------------------------------------------------- 1 | LeafletWidget.methods.addProviderTiles = function(provider, layerId, group, options) { 2 | this.layerManager.addLayer(L.tileLayer.provider(provider, options), "tile", layerId, group); 3 | }; 4 | -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_files/leafletfix-1.0.0/leafletfix.css: -------------------------------------------------------------------------------- 1 | /* Work around CSS properties introduced on img by bootstrap */ 2 | img.leaflet-tile { 3 | padding: 0; 4 | margin: 0; 5 | border-radius: 0; 6 | border: none; 7 | } 8 | .info { 9 | padding: 6px 8px; 10 | font: 14px/16px Arial, Helvetica, sans-serif; 11 | background: white; 12 | background: rgba(255,255,255,0.8); 13 | box-shadow: 0 0 15px rgba(0,0,0,0.2); 14 | border-radius: 5px; 15 | } 16 | .legend { 17 | line-height: 18px; 18 | color: #555; 19 | } 20 | .legend svg text { 21 | fill: #555; 22 | } 23 | .legend svg line { 24 | stroke: #555; 25 | } 26 | .legend i { 27 | width: 18px; 28 | height: 18px; 29 | margin-right: 4px; 30 | opacity: 0.7; 31 | display: inline-block; 32 | vertical-align: top; 33 | /*For IE 7*/ 34 | zoom: 1; 35 | *display: inline; 36 | } 37 | -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_files/rstudio_leaflet-1.3.1/images/1px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/20_movement/ice-cream_files/rstudio_leaflet-1.3.1/images/1px.png -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_files/rstudio_leaflet-1.3.1/rstudio_leaflet.css: -------------------------------------------------------------------------------- 1 | .leaflet-tooltip.leaflet-tooltip-text-only, 2 | .leaflet-tooltip.leaflet-tooltip-text-only:before, 3 | .leaflet-tooltip.leaflet-tooltip-text-only:after { 4 | background: none; 5 | border: none; 6 | box-shadow: none; 7 | } 8 | 9 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-left { 10 | margin-left: 5px; 11 | } 12 | 13 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-right { 14 | margin-left: -5px; 15 | } 16 | 17 | .leaflet-tooltip:after { 18 | border-right: 6px solid transparent; 19 | /* right: -16px; */ 20 | } 21 | 22 | .leaflet-popup-pane .leaflet-popup-tip-container { 23 | /* when the tooltip container is clicked, it is closed */ 24 | pointer-events: all; 25 | /* tooltips should display the "hand" icon, just like .leaflet-interactive*/ 26 | cursor: pointer; 27 | } 28 | 29 | /* have the widget be displayed in the right 'layer' */ 30 | .leaflet-map-pane { 31 | z-index: auto; 32 | } 33 | -------------------------------------------------------------------------------- /2021/20_movement/ice-cream_two_opt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/20_movement/ice-cream_two_opt.png -------------------------------------------------------------------------------- /2021/20_movement/icecream.R: -------------------------------------------------------------------------------- 1 | library(sf) 2 | library(readr) 3 | library(sf) 4 | library(dplyr) 5 | library(osrm) 6 | library(stplanr) 7 | library(ggplot2) 8 | library(htmltools) 9 | library(glue) 10 | library(htmlwidgets) 11 | library(webshot) 12 | library(purrr) 13 | 14 | Sys.setlocale("LC_ALL", "Hebrew") 15 | 16 | # Get Tel Aviv shapefile to extract points for routes 17 | tel_aviv_file_name <- list.files(pattern =".Aviv.+\\.shp$", recursive = TRUE) 18 | tel_aviv_file <- read_sf(paste0(tel_aviv_file_name)) 19 | 20 | # Provide relevant crs to Tel-Aviv 21 | tel_aviv_file <- st_transform(st_set_crs(tel_aviv_file, 2039), 4326) 22 | 23 | # Incomplete data (specific locations for this analysis were added manually) 24 | golda <- readxl::read_xlsx("2021/data/golda_locations.xlsx") %>% 25 | mutate(id = 1:nrow(.)) 26 | 27 | golda_sf <- golda %>% 28 | st_as_sf(coords = c("long", "lat"), crs = 4326, remove = FALSE) %>% 29 | # Get only what's in Tel-Aviv 30 | filter(lengths(st_intersects(., tel_aviv_file)) > 0) 31 | 32 | # TSP analysis based on Jerry Shannon's piece: 33 | # https://twitter.com/jerry_shannon/status/1455525819066028037/photo/1 34 | 35 | distance <- st_distance(golda_sf, golda_sf) 36 | distance <- as.matrix(distance) / 1000 37 | 38 | colnames(distance) <- golda_sf$id 39 | rownames(distance) <- golda_sf$id 40 | 41 | # covert to distance matrix of upper/lower 42 | distance <- as.dist(distance) 43 | 44 | # TSP prob & solving ------------------------------------------------------ 45 | tsp <- TSP(distance) 46 | 47 | # Playing around with different methods 48 | methods <- c( 49 | "nearest_insertion", 50 | "farthest_insertion", 51 | "cheapest_insertion", 52 | "arbitrary_insertion", 53 | "nn", 54 | "repetitive_nn", 55 | "two_opt" 56 | ) 57 | 58 | 59 | tours <- methods %>% map(function(method) { 60 | solve_TSP(tsp, method) 61 | }) 62 | 63 | # Find the optimal method (Though also I want it to be intuitive for me) 64 | dotchart(sort(c(sapply(tours, tour_length), optimal = 30)), 65 | xlab = "tour length", xlim = c(0, 35)) 66 | 67 | 68 | 69 | # Go with insertion algorithm, specifically farthest, read more here: 70 | # https://cran.r-project.org/web/packages/TSP/vignettes/TSP.pdf 71 | tour <- solve_TSP(tsp, method = "farthest_insertion") 72 | 73 | # Order of locations in tour 74 | tour_order <- as.integer(tour) 75 | 76 | # get order of addresses 77 | addresses <- golda_sf[tour_order,] 78 | 79 | 80 | # Build route 81 | golda_route <- map_dfr(seq(nrow(addresses)-1), function (n){ 82 | route( 83 | from = addresses[n,], 84 | to = addresses[n + 1,], 85 | route_fun = osrmRoute, 86 | returnclass = "sf") %>% 87 | mutate(section = n) 88 | }) 89 | 90 | # Add location labels 91 | make_label <- function(street ){ 92 | glue("
{street}
") %>% 93 | HTML()} 94 | 95 | # Map map 96 | p <- leaflet() %>% 97 | addProviderTiles("CartoDB.Positron",options = providerTileOptions(minZoom = 12)) %>% 98 | addPolylines(data = golda_route, weight = 2, color = "#080E46") %>% 99 | # Add emoji as points 100 | addLabelOnlyMarkers(data = golda_sf, label = HTML("🍦"), 101 | labelOptions = labelOptions(noHide = T, textOnly = T, 102 | "font-size" = "6px")) %>% 103 | # Add a start label 104 | addLabelOnlyMarkers(data = golda_route[1,], ~fx, ~fy, label = HTML("Start
↓"), 105 | labelOptions = labelOptions(noHide = T, direction = "top", textOnly = TRUE, 106 | style = list( 107 | "color" = "#080E46", 108 | "text-align" = "center", 109 | "font-size" = "10px", 110 | "font-face" = "bold", 111 | "border-color" = "rgba(0,0,0,0.5)"))) %>% 112 | addControl(html = paste(tags$h1(HTML("Golda locations
in Tel-Aviv 🍦"), style = "color:black; font-family:Rockwell; font-size: 26pt; padding-left: 8px; line-height: 1.2em;"), 113 | tags$div(HTML("Fastest route between all
Golda ice-cream locations
in Tel-Aviv."), style = "color:black; font-family:Segoe UI; font-size: 15pt; padding-left: 8px; margin-top:-20px")), className = "fieldset { 114 | border: 0; 115 | }", position = "topleft") %>% 116 | addControl(html = tags$div(HTML("Data: Golda • Amit_Levinson • Code"), style = "color:black; font-family:Segoe UI; font-size: 12pt; padding-left: 15px;"), className = "fieldset {border: 0;}", position = "bottomleft") 117 | 118 | 119 | # Save widget 120 | saveWidget(p, "2021/20_movement/ice-cream.html") 121 | # Save snapshot 122 | webshot("2021/20_movement/ice-cream.html", file = "2021/20_movement/ice-cream_farthest.png", zoom = 3, vwidth = 900, vheight = 700, delay = 2) 123 | 124 | -------------------------------------------------------------------------------- /2021/22_borders/borders.R: -------------------------------------------------------------------------------- 1 | library(sf) 2 | library(purrr) 3 | library(viridis) 4 | library(ggplot2) 5 | library(dplyr) 6 | library(ggtext) 7 | 8 | # Sys.setlocale("LC_ALL", "Hebrew") 9 | 10 | tel_aviv_neighborhoods_path <- list.files(pattern ="Neighbourhoods\\.shp$", recursive = TRUE) 11 | tel_aviv_neighborhoods <- read_sf(tel_aviv_neighborhoods_path) %>% 12 | st_transform(crs = 4326) 13 | 14 | # Function to count number of bordering neighbourhoods 15 | count_borders <- function (rownumber) { 16 | tel_aviv_neighborhoods[rownumber,] %>% 17 | st_touches(tel_aviv_neighborhoods) %>% 18 | unlist() %>% 19 | length() 20 | } 21 | 22 | ta <- tel_aviv_neighborhoods %>% 23 | mutate( 24 | # Wrap in purrr::possibly as it might result in NA's and throw an error if your sf is messy:( 25 | n_borders = map_dbl(seq(nrow(.)), possibly(count_borders, NA_real_)) 26 | ) 27 | 28 | yarkon_arrow <- ta %>% 29 | filter(n_borders == max(n_borders)) %>% 30 | st_centroid() %>% 31 | st_coordinates() 32 | 33 | 34 | ta %>% 35 | ggplot()+ 36 | geom_sf(aes(fill = n_borders), color = "gray5", size = 0.1)+ 37 | annotate(geom = "curve", x = yarkon_arrow[1] -0.003, xend = yarkon_arrow[1] , y = yarkon_arrow[2] - 0.015, yend = yarkon_arrow[2]-0.003, 38 | curvature =.1, color = "gray25", size = 0.5, arrow = arrow(length = unit(2, "mm")))+ 39 | geom_richtext(aes(x = yarkon_arrow[1] -0.003, y = yarkon_arrow[2] - 0.0155, label = "The *Yarkon*, bordering
15 other neighborhoods", hjust = 0, vjust = 1),label.color = NA, fill = NA, size = 6, family = "Mukta", color = "gray35")+ 40 | labs(title = "Bordering Neighborhoods in Tel-Aviv", 41 | subtitle = "Number of neighborhoods each neighborhood borders in Tel-Aviv", 42 | caption = "@Amit_Levinson" 43 | )+ 44 | scale_fill_viridis(name = "# borders",option="magma")+ 45 | guides(fill = guide_colorbar(barheight = unit(2.2, units = "mm"), barwidth = unit(45, units = "mm"), 46 | ticks.colour = "gray25", title.position = "top", label.position = "bottom", 47 | title.hjust = 0.5))+ 48 | theme_void()+ 49 | theme( 50 | text = element_text(family = "Mukta"), 51 | plot.title = element_text(size = 24, face = "bold", family = "Lora"), 52 | plot.subtitle = element_text(size = 19), 53 | plot.caption = element_text(size = 14, color = "gray35", hjust = 1), 54 | plot.title.position = "plot", 55 | legend.position = "bottom", 56 | legend.title = element_text(size = 18), 57 | legend.text = element_text(size = 14), 58 | plot.background = element_rect(fill = "white", color = NA), 59 | panel.background = element_rect(fill = "white", color = NA), 60 | plot.margin = margin(4,2,4,2,"mm") 61 | ) 62 | 63 | ggsave("2021/22_borders/borders.png", height = 11, width = 9) 64 | -------------------------------------------------------------------------------- /2021/22_borders/borders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/22_borders/borders.png -------------------------------------------------------------------------------- /2021/25_interactive/elderly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/25_interactive/elderly.png -------------------------------------------------------------------------------- /2021/25_interactive/elderly_files/Proj4Leaflet-1.0.1/proj4leaflet.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | var L, proj4; 3 | if (typeof define === 'function' && define.amd) { 4 | // AMD 5 | define(['leaflet', 'proj4'], factory); 6 | } else if (typeof module === 'object' && typeof module.exports === "object") { 7 | // Node/CommonJS 8 | L = require('leaflet'); 9 | proj4 = require('proj4'); 10 | module.exports = factory(L, proj4); 11 | } else { 12 | // Browser globals 13 | if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined') 14 | throw 'Leaflet and proj4 must be loaded first'; 15 | factory(window.L, window.proj4); 16 | } 17 | }(function (L, proj4) { 18 | if (proj4.__esModule && proj4.default) { 19 | // If proj4 was bundled as an ES6 module, unwrap it to get 20 | // to the actual main proj4 object. 21 | // See discussion in https://github.com/kartena/Proj4Leaflet/pull/147 22 | proj4 = proj4.default; 23 | } 24 | 25 | L.Proj = {}; 26 | 27 | L.Proj._isProj4Obj = function(a) { 28 | return (typeof a.inverse !== 'undefined' && 29 | typeof a.forward !== 'undefined'); 30 | }; 31 | 32 | L.Proj.Projection = L.Class.extend({ 33 | initialize: function(code, def, bounds) { 34 | var isP4 = L.Proj._isProj4Obj(code); 35 | this._proj = isP4 ? code : this._projFromCodeDef(code, def); 36 | this.bounds = isP4 ? def : bounds; 37 | }, 38 | 39 | project: function (latlng) { 40 | var point = this._proj.forward([latlng.lng, latlng.lat]); 41 | return new L.Point(point[0], point[1]); 42 | }, 43 | 44 | unproject: function (point, unbounded) { 45 | var point2 = this._proj.inverse([point.x, point.y]); 46 | return new L.LatLng(point2[1], point2[0], unbounded); 47 | }, 48 | 49 | _projFromCodeDef: function(code, def) { 50 | if (def) { 51 | proj4.defs(code, def); 52 | } else if (proj4.defs[code] === undefined) { 53 | var urn = code.split(':'); 54 | if (urn.length > 3) { 55 | code = urn[urn.length - 3] + ':' + urn[urn.length - 1]; 56 | } 57 | if (proj4.defs[code] === undefined) { 58 | throw 'No projection definition for code ' + code; 59 | } 60 | } 61 | 62 | return proj4(code); 63 | } 64 | }); 65 | 66 | L.Proj.CRS = L.Class.extend({ 67 | includes: L.CRS, 68 | 69 | options: { 70 | transformation: new L.Transformation(1, 0, -1, 0) 71 | }, 72 | 73 | initialize: function(a, b, c) { 74 | var code, 75 | proj, 76 | def, 77 | options; 78 | 79 | if (L.Proj._isProj4Obj(a)) { 80 | proj = a; 81 | code = proj.srsCode; 82 | options = b || {}; 83 | 84 | this.projection = new L.Proj.Projection(proj, options.bounds); 85 | } else { 86 | code = a; 87 | def = b; 88 | options = c || {}; 89 | this.projection = new L.Proj.Projection(code, def, options.bounds); 90 | } 91 | 92 | L.Util.setOptions(this, options); 93 | this.code = code; 94 | this.transformation = this.options.transformation; 95 | 96 | if (this.options.origin) { 97 | this.transformation = 98 | new L.Transformation(1, -this.options.origin[0], 99 | -1, this.options.origin[1]); 100 | } 101 | 102 | if (this.options.scales) { 103 | this._scales = this.options.scales; 104 | } else if (this.options.resolutions) { 105 | this._scales = []; 106 | for (var i = this.options.resolutions.length - 1; i >= 0; i--) { 107 | if (this.options.resolutions[i]) { 108 | this._scales[i] = 1 / this.options.resolutions[i]; 109 | } 110 | } 111 | } 112 | 113 | this.infinite = !this.options.bounds; 114 | 115 | }, 116 | 117 | scale: function(zoom) { 118 | var iZoom = Math.floor(zoom), 119 | baseScale, 120 | nextScale, 121 | scaleDiff, 122 | zDiff; 123 | if (zoom === iZoom) { 124 | return this._scales[zoom]; 125 | } else { 126 | // Non-integer zoom, interpolate 127 | baseScale = this._scales[iZoom]; 128 | nextScale = this._scales[iZoom + 1]; 129 | scaleDiff = nextScale - baseScale; 130 | zDiff = (zoom - iZoom); 131 | return baseScale + scaleDiff * zDiff; 132 | } 133 | }, 134 | 135 | zoom: function(scale) { 136 | // Find closest number in this._scales, down 137 | var downScale = this._closestElement(this._scales, scale), 138 | downZoom = this._scales.indexOf(downScale), 139 | nextScale, 140 | nextZoom, 141 | scaleDiff; 142 | // Check if scale is downScale => return array index 143 | if (scale === downScale) { 144 | return downZoom; 145 | } 146 | if (downScale === undefined) { 147 | return -Infinity; 148 | } 149 | // Interpolate 150 | nextZoom = downZoom + 1; 151 | nextScale = this._scales[nextZoom]; 152 | if (nextScale === undefined) { 153 | return Infinity; 154 | } 155 | scaleDiff = nextScale - downScale; 156 | return (scale - downScale) / scaleDiff + downZoom; 157 | }, 158 | 159 | distance: L.CRS.Earth.distance, 160 | 161 | R: L.CRS.Earth.R, 162 | 163 | /* Get the closest lowest element in an array */ 164 | _closestElement: function(array, element) { 165 | var low; 166 | for (var i = array.length; i--;) { 167 | if (array[i] <= element && (low === undefined || low < array[i])) { 168 | low = array[i]; 169 | } 170 | } 171 | return low; 172 | } 173 | }); 174 | 175 | L.Proj.GeoJSON = L.GeoJSON.extend({ 176 | initialize: function(geojson, options) { 177 | this._callLevel = 0; 178 | L.GeoJSON.prototype.initialize.call(this, geojson, options); 179 | }, 180 | 181 | addData: function(geojson) { 182 | var crs; 183 | 184 | if (geojson) { 185 | if (geojson.crs && geojson.crs.type === 'name') { 186 | crs = new L.Proj.CRS(geojson.crs.properties.name); 187 | } else if (geojson.crs && geojson.crs.type) { 188 | crs = new L.Proj.CRS(geojson.crs.type + ':' + geojson.crs.properties.code); 189 | } 190 | 191 | if (crs !== undefined) { 192 | this.options.coordsToLatLng = function(coords) { 193 | var point = L.point(coords[0], coords[1]); 194 | return crs.projection.unproject(point); 195 | }; 196 | } 197 | } 198 | 199 | // Base class' addData might call us recursively, but 200 | // CRS shouldn't be cleared in that case, since CRS applies 201 | // to the whole GeoJSON, inluding sub-features. 202 | this._callLevel++; 203 | try { 204 | L.GeoJSON.prototype.addData.call(this, geojson); 205 | } finally { 206 | this._callLevel--; 207 | if (this._callLevel === 0) { 208 | delete this.options.coordsToLatLng; 209 | } 210 | } 211 | } 212 | }); 213 | 214 | L.Proj.geoJson = function(geojson, options) { 215 | return new L.Proj.GeoJSON(geojson, options); 216 | }; 217 | 218 | L.Proj.ImageOverlay = L.ImageOverlay.extend({ 219 | initialize: function (url, bounds, options) { 220 | L.ImageOverlay.prototype.initialize.call(this, url, null, options); 221 | this._projectedBounds = bounds; 222 | }, 223 | 224 | // Danger ahead: Overriding internal methods in Leaflet. 225 | // Decided to do this rather than making a copy of L.ImageOverlay 226 | // and doing very tiny modifications to it. 227 | // Future will tell if this was wise or not. 228 | _animateZoom: function (event) { 229 | var scale = this._map.getZoomScale(event.zoom); 230 | var northWest = L.point(this._projectedBounds.min.x, this._projectedBounds.max.y); 231 | var offset = this._projectedToNewLayerPoint(northWest, event.zoom, event.center); 232 | 233 | L.DomUtil.setTransform(this._image, offset, scale); 234 | }, 235 | 236 | _reset: function () { 237 | var zoom = this._map.getZoom(); 238 | var pixelOrigin = this._map.getPixelOrigin(); 239 | var bounds = L.bounds( 240 | this._transform(this._projectedBounds.min, zoom)._subtract(pixelOrigin), 241 | this._transform(this._projectedBounds.max, zoom)._subtract(pixelOrigin) 242 | ); 243 | var size = bounds.getSize(); 244 | 245 | L.DomUtil.setPosition(this._image, bounds.min); 246 | this._image.style.width = size.x + 'px'; 247 | this._image.style.height = size.y + 'px'; 248 | }, 249 | 250 | _projectedToNewLayerPoint: function (point, zoom, center) { 251 | var viewHalf = this._map.getSize()._divideBy(2); 252 | var newTopLeft = this._map.project(center, zoom)._subtract(viewHalf)._round(); 253 | var topLeft = newTopLeft.add(this._map._getMapPanePos()); 254 | 255 | return this._transform(point, zoom)._subtract(topLeft); 256 | }, 257 | 258 | _transform: function (point, zoom) { 259 | var crs = this._map.options.crs; 260 | var transformation = crs.transformation; 261 | var scale = crs.scale(zoom); 262 | 263 | return transformation.transform(point, scale); 264 | } 265 | }); 266 | 267 | L.Proj.imageOverlay = function (url, bounds, options) { 268 | return new L.Proj.ImageOverlay(url, bounds, options); 269 | }; 270 | 271 | return L.Proj; 272 | })); 273 | -------------------------------------------------------------------------------- /2021/25_interactive/elderly_files/leaflet-1.3.1/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/25_interactive/elderly_files/leaflet-1.3.1/images/layers-2x.png -------------------------------------------------------------------------------- /2021/25_interactive/elderly_files/leaflet-1.3.1/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/25_interactive/elderly_files/leaflet-1.3.1/images/layers.png -------------------------------------------------------------------------------- /2021/25_interactive/elderly_files/leaflet-1.3.1/images/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/25_interactive/elderly_files/leaflet-1.3.1/images/marker-icon-2x.png -------------------------------------------------------------------------------- /2021/25_interactive/elderly_files/leaflet-1.3.1/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/25_interactive/elderly_files/leaflet-1.3.1/images/marker-icon.png -------------------------------------------------------------------------------- /2021/25_interactive/elderly_files/leaflet-1.3.1/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/25_interactive/elderly_files/leaflet-1.3.1/images/marker-shadow.png -------------------------------------------------------------------------------- /2021/25_interactive/elderly_files/leaflet-providers-plugin-2.0.4.1/leaflet-providers-plugin.js: -------------------------------------------------------------------------------- 1 | LeafletWidget.methods.addProviderTiles = function(provider, layerId, group, options) { 2 | this.layerManager.addLayer(L.tileLayer.provider(provider, options), "tile", layerId, group); 3 | }; 4 | -------------------------------------------------------------------------------- /2021/25_interactive/elderly_files/leafletfix-1.0.0/leafletfix.css: -------------------------------------------------------------------------------- 1 | /* Work around CSS properties introduced on img by bootstrap */ 2 | img.leaflet-tile { 3 | padding: 0; 4 | margin: 0; 5 | border-radius: 0; 6 | border: none; 7 | } 8 | .info { 9 | padding: 6px 8px; 10 | font: 14px/16px Arial, Helvetica, sans-serif; 11 | background: white; 12 | background: rgba(255,255,255,0.8); 13 | box-shadow: 0 0 15px rgba(0,0,0,0.2); 14 | border-radius: 5px; 15 | } 16 | .legend { 17 | line-height: 18px; 18 | color: #555; 19 | } 20 | .legend svg text { 21 | fill: #555; 22 | } 23 | .legend svg line { 24 | stroke: #555; 25 | } 26 | .legend i { 27 | width: 18px; 28 | height: 18px; 29 | margin-right: 4px; 30 | opacity: 0.7; 31 | display: inline-block; 32 | vertical-align: top; 33 | /*For IE 7*/ 34 | zoom: 1; 35 | *display: inline; 36 | } 37 | -------------------------------------------------------------------------------- /2021/25_interactive/elderly_files/rstudio_leaflet-1.3.1/images/1px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/25_interactive/elderly_files/rstudio_leaflet-1.3.1/images/1px.png -------------------------------------------------------------------------------- /2021/25_interactive/elderly_files/rstudio_leaflet-1.3.1/rstudio_leaflet.css: -------------------------------------------------------------------------------- 1 | .leaflet-tooltip.leaflet-tooltip-text-only, 2 | .leaflet-tooltip.leaflet-tooltip-text-only:before, 3 | .leaflet-tooltip.leaflet-tooltip-text-only:after { 4 | background: none; 5 | border: none; 6 | box-shadow: none; 7 | } 8 | 9 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-left { 10 | margin-left: 5px; 11 | } 12 | 13 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-right { 14 | margin-left: -5px; 15 | } 16 | 17 | .leaflet-tooltip:after { 18 | border-right: 6px solid transparent; 19 | /* right: -16px; */ 20 | } 21 | 22 | .leaflet-popup-pane .leaflet-popup-tip-container { 23 | /* when the tooltip container is clicked, it is closed */ 24 | pointer-events: all; 25 | /* tooltips should display the "hand" icon, just like .leaflet-interactive*/ 26 | cursor: pointer; 27 | } 28 | 29 | /* have the widget be displayed in the right 'layer' */ 30 | .leaflet-map-pane { 31 | z-index: auto; 32 | } 33 | -------------------------------------------------------------------------------- /2021/25_interactive/src.R: -------------------------------------------------------------------------------- 1 | library(sf) 2 | library(jsonlite) 3 | library(httr) 4 | library(purrr) 5 | library(dplyr) 6 | library(ggplot2) 7 | library(leaflet) 8 | library(glue) 9 | library(htmlwidgets) 10 | library(webshot) 11 | 12 | # Set for Hebrew characters 13 | # Sys.setlocale("LC_ALL", "Hebrew") 14 | 15 | # Bus stops from TA api 16 | bus_stopsapiraw <- GET("https://gisn.tel-aviv.gov.il/arcgis/rest/services/IView2/MapServer/956/query?where=1%3D1&outFields=*&f=json") 17 | bus_apilist <- fromJSON(content(bus_stopsapiraw, "text"), simplifyVector = FALSE) 18 | bus_stops <- map_dfr(bus_apilist$features, pluck("attributes")) %>% 19 | st_as_sf(coords = c("stop_lon", "stop_lat"), crs = 4326) %>% 20 | st_transform(crs = 2039) %>% 21 | mutate(id = 1:nrow(.)) 22 | 23 | # Get the API information from Tel-Aviv municipality website for elderly locations 24 | elderly_info <- data.frame( 25 | apiurl = c( 26 | "https://gisn.tel-aviv.gov.il/arcgis/rest/services/IView2/MapServer/600/query?where=1%3D1&outFields=*&f=json", 27 | "https://gisn.tel-aviv.gov.il/arcgis/rest/services/IView2/MapServer/581/query?where=1%3D1&outFields=*&f=json", 28 | "https://gisn.tel-aviv.gov.il/arcgis/rest/services/IView2/MapServer/855/query?where=1%3D1&outFields=*&f=json" 29 | ), 30 | apiname = c("elderly_clubs","geriatric_day_center", "programs_for_elderly" ) 31 | ) 32 | 33 | 34 | # Function to extract, clean and transform to sf the api call of elderly program locations 35 | clean_ta_api <- function(apiurl, apiname) { 36 | apiraw <- GET(apiurl) 37 | 38 | apilist <- fromJSON(content(apiraw, "text"), simplifyVector = FALSE) 39 | 40 | sf_data <- map_dfr(apilist$features, pluck("geometry")) %>% 41 | mutate( 42 | shem = map_chr(apilist$features, pluck, "attributes", "shem", .default = NA), 43 | location_name = apiname 44 | ) %>% 45 | st_as_sf(coords = c("x", "y"), crs = 2039) 46 | 47 | return(sf_data) 48 | } 49 | 50 | # Get the data 51 | elderly <- map2_dfr(elderly_info$apiurl, elderly_info$apiname, clean_ta_api) %>% 52 | distinct(shem, location_name, geometry) 53 | 54 | # Calculate distances from each elderly center to the nearest bus stop 55 | distances <- st_distance(bus_stops, elderly) %>% 56 | as_tibble() 57 | 58 | # Get the minimum distance, i.e. the nearest bus stop 59 | elderly_with_info <- elderly %>% 60 | mutate(distance_to_bus = map_dbl(distances, function(x) min(x))) %>% 61 | st_transform(crs = 4326) 62 | 63 | bus_stops_wgs <- bus_stops %>% 64 | st_transform(crs = 4326) 65 | 66 | distance_label <- glue("{round(elderly_with_info$distance_to_bus, 1)}m") %>% 67 | map(., htmltools::HTML) 68 | 69 | pal <- colorNumeric( 70 | palette = RColorBrewer::brewer.pal(9, "Blues"), 71 | domain = elderly_with_info$distance_to_bus) 72 | 73 | open_labels <- elderly_with_info %>% 74 | arrange(-distance_to_bus) %>% 75 | slice(c(1,3)) %>% 76 | mutate(distance_label_open = glue("{round(distance_to_bus, 1)}m"), 77 | distance_label_open = lapply(distance_label_open, HTML)) 78 | 79 | 80 | p <- leaflet() %>% 81 | addProviderTiles("CartoDB.Positron",options = providerTileOptions(minZoom = 12)) %>% 82 | addCircles(data = bus_stops_wgs, weight =1, color = "#696969", radius = 1, opacity = 0.5) %>% 83 | addCircleMarkers(data = elderly_with_info, weight = 4, radius = 2, color = ~pal(distance_to_bus), fillColor = ~pal(distance_to_bus), label = distance_label, opacity = 1, labelOptions = labelOptions( 84 | style = list( 85 | "font-size" = "14px", 86 | "border-color" = "rgba(0,0,0,0.5)"))) %>% 87 | addLabelOnlyMarkers(data = open_labels, label = open_labels$distance_label_open, 88 | labelOptions = labelOptions(noHide = T, direction = "top", 89 | style = list( 90 | "font-size" = "11px", 91 | "border-color" = "rgba(0,0,0,0.5)"))) %>% 92 | addControl(html = paste(tags$h1(HTML("Distance from elderly
program locations to
the nearest bus stop"), style = "color:black; font-family:Alegreya; font-size: 24pt; padding-left: 8px; line-height: 1.1em;")), className = "fieldset { 93 | border: 0; 94 | }", position = "topleft") %>% 95 | addLegend( 96 | title = "Distance (m)", 97 | data = elderly_with_info, 98 | position = "bottomright", 99 | pal = pal, values = ~ elderly_with_info$distance_to_bus, 100 | bins = c(100,200,300)) 101 | 102 | 103 | # Save widget 104 | saveWidget(p, "2021/25_interactive/elderly.html") 105 | # Save snapshot 106 | webshot("2021/25_interactive/elderly.html", file = "2021/25_interactive/elderly.png", vwidth = 700, vheight = 800, delay = 2) 107 | -------------------------------------------------------------------------------- /2021/data/Crime-map-2016_2021.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/Crime-map-2016_2021.xlsx -------------------------------------------------------------------------------- /2021/data/golda_locations.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/golda_locations.xlsx -------------------------------------------------------------------------------- /2021/data/ta-shapefile/gv_Tel_Aviv-Yafo_27.10.14.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/ta-shapefile/gv_Tel_Aviv-Yafo_27.10.14.dbf -------------------------------------------------------------------------------- /2021/data/ta-shapefile/gv_Tel_Aviv-Yafo_27.10.14.jgw: -------------------------------------------------------------------------------- 1 | 3.03925388213476 2 | -0.00088827221119 3 | -0.00088845076055 4 | -3.03986479491399 5 | 174915.71561200556000 6 | 680001.49658626493000 7 | -------------------------------------------------------------------------------- /2021/data/ta-shapefile/gv_Tel_Aviv-Yafo_27.10.14.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/ta-shapefile/gv_Tel_Aviv-Yafo_27.10.14.shp -------------------------------------------------------------------------------- /2021/data/ta-shapefile/gv_Tel_Aviv-Yafo_27.10.14.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/ta-shapefile/gv_Tel_Aviv-Yafo_27.10.14.shx -------------------------------------------------------------------------------- /2021/data/tatrees/%D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.cpg: -------------------------------------------------------------------------------- 1 | UTF-8 -------------------------------------------------------------------------------- /2021/data/tatrees/%D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/tatrees/%D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.dbf -------------------------------------------------------------------------------- /2021/data/tatrees/%D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.prj: -------------------------------------------------------------------------------- 1 | PROJCS["WGS_1984_Web_Mercator_Auxiliary_Sphere",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Mercator_Auxiliary_Sphere"],PARAMETER["False_Easting",0.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",0.0],PARAMETER["Standard_Parallel_1",0.0],PARAMETER["Auxiliary_Sphere_Type",0.0],UNIT["Meter",1.0]] -------------------------------------------------------------------------------- /2021/data/tatrees/%D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/tatrees/%D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.shp -------------------------------------------------------------------------------- /2021/data/tatrees/%D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/tatrees/%D7%A2%D7%A6%D7%99_%D7%9E%D7%95%D7%A8%D7%A9%D7%AA.shx -------------------------------------------------------------------------------- /2021/data/wave/export.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/wave/export.xlsx -------------------------------------------------------------------------------- /2021/data/wave/tsunami 5 meter line.cpg: -------------------------------------------------------------------------------- 1 | utf-8 -------------------------------------------------------------------------------- /2021/data/wave/tsunami 5 meter line.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/wave/tsunami 5 meter line.dbf -------------------------------------------------------------------------------- /2021/data/wave/tsunami 5 meter line.prj: -------------------------------------------------------------------------------- 1 | PROJCS["WGS_1984_UTM_Zone_36N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",33.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] -------------------------------------------------------------------------------- /2021/data/wave/tsunami 5 meter line.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/wave/tsunami 5 meter line.shp -------------------------------------------------------------------------------- /2021/data/wave/tsunami 5 meter line.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/data/wave/tsunami 5 meter line.shx -------------------------------------------------------------------------------- /2021/messing-around/ggmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/ggmap.png -------------------------------------------------------------------------------- /2021/messing-around/ggmap_polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/ggmap_polygon.png -------------------------------------------------------------------------------- /2021/messing-around/ggmap_polygon_clean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/ggmap_polygon_clean.png -------------------------------------------------------------------------------- /2021/messing-around/israel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/israel.png -------------------------------------------------------------------------------- /2021/messing-around/israelpre67.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/israelpre67.png -------------------------------------------------------------------------------- /2021/messing-around/leaflet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/leaflet.png -------------------------------------------------------------------------------- /2021/messing-around/leaflet_files/Proj4Leaflet-1.0.1/proj4leaflet.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | var L, proj4; 3 | if (typeof define === 'function' && define.amd) { 4 | // AMD 5 | define(['leaflet', 'proj4'], factory); 6 | } else if (typeof module === 'object' && typeof module.exports === "object") { 7 | // Node/CommonJS 8 | L = require('leaflet'); 9 | proj4 = require('proj4'); 10 | module.exports = factory(L, proj4); 11 | } else { 12 | // Browser globals 13 | if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined') 14 | throw 'Leaflet and proj4 must be loaded first'; 15 | factory(window.L, window.proj4); 16 | } 17 | }(function (L, proj4) { 18 | if (proj4.__esModule && proj4.default) { 19 | // If proj4 was bundled as an ES6 module, unwrap it to get 20 | // to the actual main proj4 object. 21 | // See discussion in https://github.com/kartena/Proj4Leaflet/pull/147 22 | proj4 = proj4.default; 23 | } 24 | 25 | L.Proj = {}; 26 | 27 | L.Proj._isProj4Obj = function(a) { 28 | return (typeof a.inverse !== 'undefined' && 29 | typeof a.forward !== 'undefined'); 30 | }; 31 | 32 | L.Proj.Projection = L.Class.extend({ 33 | initialize: function(code, def, bounds) { 34 | var isP4 = L.Proj._isProj4Obj(code); 35 | this._proj = isP4 ? code : this._projFromCodeDef(code, def); 36 | this.bounds = isP4 ? def : bounds; 37 | }, 38 | 39 | project: function (latlng) { 40 | var point = this._proj.forward([latlng.lng, latlng.lat]); 41 | return new L.Point(point[0], point[1]); 42 | }, 43 | 44 | unproject: function (point, unbounded) { 45 | var point2 = this._proj.inverse([point.x, point.y]); 46 | return new L.LatLng(point2[1], point2[0], unbounded); 47 | }, 48 | 49 | _projFromCodeDef: function(code, def) { 50 | if (def) { 51 | proj4.defs(code, def); 52 | } else if (proj4.defs[code] === undefined) { 53 | var urn = code.split(':'); 54 | if (urn.length > 3) { 55 | code = urn[urn.length - 3] + ':' + urn[urn.length - 1]; 56 | } 57 | if (proj4.defs[code] === undefined) { 58 | throw 'No projection definition for code ' + code; 59 | } 60 | } 61 | 62 | return proj4(code); 63 | } 64 | }); 65 | 66 | L.Proj.CRS = L.Class.extend({ 67 | includes: L.CRS, 68 | 69 | options: { 70 | transformation: new L.Transformation(1, 0, -1, 0) 71 | }, 72 | 73 | initialize: function(a, b, c) { 74 | var code, 75 | proj, 76 | def, 77 | options; 78 | 79 | if (L.Proj._isProj4Obj(a)) { 80 | proj = a; 81 | code = proj.srsCode; 82 | options = b || {}; 83 | 84 | this.projection = new L.Proj.Projection(proj, options.bounds); 85 | } else { 86 | code = a; 87 | def = b; 88 | options = c || {}; 89 | this.projection = new L.Proj.Projection(code, def, options.bounds); 90 | } 91 | 92 | L.Util.setOptions(this, options); 93 | this.code = code; 94 | this.transformation = this.options.transformation; 95 | 96 | if (this.options.origin) { 97 | this.transformation = 98 | new L.Transformation(1, -this.options.origin[0], 99 | -1, this.options.origin[1]); 100 | } 101 | 102 | if (this.options.scales) { 103 | this._scales = this.options.scales; 104 | } else if (this.options.resolutions) { 105 | this._scales = []; 106 | for (var i = this.options.resolutions.length - 1; i >= 0; i--) { 107 | if (this.options.resolutions[i]) { 108 | this._scales[i] = 1 / this.options.resolutions[i]; 109 | } 110 | } 111 | } 112 | 113 | this.infinite = !this.options.bounds; 114 | 115 | }, 116 | 117 | scale: function(zoom) { 118 | var iZoom = Math.floor(zoom), 119 | baseScale, 120 | nextScale, 121 | scaleDiff, 122 | zDiff; 123 | if (zoom === iZoom) { 124 | return this._scales[zoom]; 125 | } else { 126 | // Non-integer zoom, interpolate 127 | baseScale = this._scales[iZoom]; 128 | nextScale = this._scales[iZoom + 1]; 129 | scaleDiff = nextScale - baseScale; 130 | zDiff = (zoom - iZoom); 131 | return baseScale + scaleDiff * zDiff; 132 | } 133 | }, 134 | 135 | zoom: function(scale) { 136 | // Find closest number in this._scales, down 137 | var downScale = this._closestElement(this._scales, scale), 138 | downZoom = this._scales.indexOf(downScale), 139 | nextScale, 140 | nextZoom, 141 | scaleDiff; 142 | // Check if scale is downScale => return array index 143 | if (scale === downScale) { 144 | return downZoom; 145 | } 146 | if (downScale === undefined) { 147 | return -Infinity; 148 | } 149 | // Interpolate 150 | nextZoom = downZoom + 1; 151 | nextScale = this._scales[nextZoom]; 152 | if (nextScale === undefined) { 153 | return Infinity; 154 | } 155 | scaleDiff = nextScale - downScale; 156 | return (scale - downScale) / scaleDiff + downZoom; 157 | }, 158 | 159 | distance: L.CRS.Earth.distance, 160 | 161 | R: L.CRS.Earth.R, 162 | 163 | /* Get the closest lowest element in an array */ 164 | _closestElement: function(array, element) { 165 | var low; 166 | for (var i = array.length; i--;) { 167 | if (array[i] <= element && (low === undefined || low < array[i])) { 168 | low = array[i]; 169 | } 170 | } 171 | return low; 172 | } 173 | }); 174 | 175 | L.Proj.GeoJSON = L.GeoJSON.extend({ 176 | initialize: function(geojson, options) { 177 | this._callLevel = 0; 178 | L.GeoJSON.prototype.initialize.call(this, geojson, options); 179 | }, 180 | 181 | addData: function(geojson) { 182 | var crs; 183 | 184 | if (geojson) { 185 | if (geojson.crs && geojson.crs.type === 'name') { 186 | crs = new L.Proj.CRS(geojson.crs.properties.name); 187 | } else if (geojson.crs && geojson.crs.type) { 188 | crs = new L.Proj.CRS(geojson.crs.type + ':' + geojson.crs.properties.code); 189 | } 190 | 191 | if (crs !== undefined) { 192 | this.options.coordsToLatLng = function(coords) { 193 | var point = L.point(coords[0], coords[1]); 194 | return crs.projection.unproject(point); 195 | }; 196 | } 197 | } 198 | 199 | // Base class' addData might call us recursively, but 200 | // CRS shouldn't be cleared in that case, since CRS applies 201 | // to the whole GeoJSON, inluding sub-features. 202 | this._callLevel++; 203 | try { 204 | L.GeoJSON.prototype.addData.call(this, geojson); 205 | } finally { 206 | this._callLevel--; 207 | if (this._callLevel === 0) { 208 | delete this.options.coordsToLatLng; 209 | } 210 | } 211 | } 212 | }); 213 | 214 | L.Proj.geoJson = function(geojson, options) { 215 | return new L.Proj.GeoJSON(geojson, options); 216 | }; 217 | 218 | L.Proj.ImageOverlay = L.ImageOverlay.extend({ 219 | initialize: function (url, bounds, options) { 220 | L.ImageOverlay.prototype.initialize.call(this, url, null, options); 221 | this._projectedBounds = bounds; 222 | }, 223 | 224 | // Danger ahead: Overriding internal methods in Leaflet. 225 | // Decided to do this rather than making a copy of L.ImageOverlay 226 | // and doing very tiny modifications to it. 227 | // Future will tell if this was wise or not. 228 | _animateZoom: function (event) { 229 | var scale = this._map.getZoomScale(event.zoom); 230 | var northWest = L.point(this._projectedBounds.min.x, this._projectedBounds.max.y); 231 | var offset = this._projectedToNewLayerPoint(northWest, event.zoom, event.center); 232 | 233 | L.DomUtil.setTransform(this._image, offset, scale); 234 | }, 235 | 236 | _reset: function () { 237 | var zoom = this._map.getZoom(); 238 | var pixelOrigin = this._map.getPixelOrigin(); 239 | var bounds = L.bounds( 240 | this._transform(this._projectedBounds.min, zoom)._subtract(pixelOrigin), 241 | this._transform(this._projectedBounds.max, zoom)._subtract(pixelOrigin) 242 | ); 243 | var size = bounds.getSize(); 244 | 245 | L.DomUtil.setPosition(this._image, bounds.min); 246 | this._image.style.width = size.x + 'px'; 247 | this._image.style.height = size.y + 'px'; 248 | }, 249 | 250 | _projectedToNewLayerPoint: function (point, zoom, center) { 251 | var viewHalf = this._map.getSize()._divideBy(2); 252 | var newTopLeft = this._map.project(center, zoom)._subtract(viewHalf)._round(); 253 | var topLeft = newTopLeft.add(this._map._getMapPanePos()); 254 | 255 | return this._transform(point, zoom)._subtract(topLeft); 256 | }, 257 | 258 | _transform: function (point, zoom) { 259 | var crs = this._map.options.crs; 260 | var transformation = crs.transformation; 261 | var scale = crs.scale(zoom); 262 | 263 | return transformation.transform(point, scale); 264 | } 265 | }); 266 | 267 | L.Proj.imageOverlay = function (url, bounds, options) { 268 | return new L.Proj.ImageOverlay(url, bounds, options); 269 | }; 270 | 271 | return L.Proj; 272 | })); 273 | -------------------------------------------------------------------------------- /2021/messing-around/leaflet_files/leaflet-1.3.1/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/leaflet_files/leaflet-1.3.1/images/layers-2x.png -------------------------------------------------------------------------------- /2021/messing-around/leaflet_files/leaflet-1.3.1/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/leaflet_files/leaflet-1.3.1/images/layers.png -------------------------------------------------------------------------------- /2021/messing-around/leaflet_files/leaflet-1.3.1/images/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/leaflet_files/leaflet-1.3.1/images/marker-icon-2x.png -------------------------------------------------------------------------------- /2021/messing-around/leaflet_files/leaflet-1.3.1/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/leaflet_files/leaflet-1.3.1/images/marker-icon.png -------------------------------------------------------------------------------- /2021/messing-around/leaflet_files/leaflet-1.3.1/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/leaflet_files/leaflet-1.3.1/images/marker-shadow.png -------------------------------------------------------------------------------- /2021/messing-around/leaflet_files/leafletfix-1.0.0/leafletfix.css: -------------------------------------------------------------------------------- 1 | /* Work around CSS properties introduced on img by bootstrap */ 2 | img.leaflet-tile { 3 | padding: 0; 4 | margin: 0; 5 | border-radius: 0; 6 | border: none; 7 | } 8 | .info { 9 | padding: 6px 8px; 10 | font: 14px/16px Arial, Helvetica, sans-serif; 11 | background: white; 12 | background: rgba(255,255,255,0.8); 13 | box-shadow: 0 0 15px rgba(0,0,0,0.2); 14 | border-radius: 5px; 15 | } 16 | .legend { 17 | line-height: 18px; 18 | color: #555; 19 | } 20 | .legend svg text { 21 | fill: #555; 22 | } 23 | .legend svg line { 24 | stroke: #555; 25 | } 26 | .legend i { 27 | width: 18px; 28 | height: 18px; 29 | margin-right: 4px; 30 | opacity: 0.7; 31 | display: inline-block; 32 | vertical-align: top; 33 | /*For IE 7*/ 34 | zoom: 1; 35 | *display: inline; 36 | } 37 | -------------------------------------------------------------------------------- /2021/messing-around/leaflet_files/rstudio_leaflet-1.3.1/images/1px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/leaflet_files/rstudio_leaflet-1.3.1/images/1px.png -------------------------------------------------------------------------------- /2021/messing-around/leaflet_files/rstudio_leaflet-1.3.1/rstudio_leaflet.css: -------------------------------------------------------------------------------- 1 | .leaflet-tooltip.leaflet-tooltip-text-only, 2 | .leaflet-tooltip.leaflet-tooltip-text-only:before, 3 | .leaflet-tooltip.leaflet-tooltip-text-only:after { 4 | background: none; 5 | border: none; 6 | box-shadow: none; 7 | } 8 | 9 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-left { 10 | margin-left: 5px; 11 | } 12 | 13 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-right { 14 | margin-left: -5px; 15 | } 16 | 17 | .leaflet-tooltip:after { 18 | border-right: 6px solid transparent; 19 | /* right: -16px; */ 20 | } 21 | 22 | .leaflet-popup-pane .leaflet-popup-tip-container { 23 | /* when the tooltip container is clicked, it is closed */ 24 | pointer-events: all; 25 | /* tooltips should display the "hand" icon, just like .leaflet-interactive*/ 26 | cursor: pointer; 27 | } 28 | 29 | /* have the widget be displayed in the right 'layer' */ 30 | .leaflet-map-pane { 31 | z-index: auto; 32 | } 33 | -------------------------------------------------------------------------------- /2021/messing-around/telaviv_tmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2021/messing-around/telaviv_tmap.png -------------------------------------------------------------------------------- /2021/messing-around/warmup.R: -------------------------------------------------------------------------------- 1 | 2 | # Just some sf objects and mapping ---------------------------------------- 3 | 4 | library(sf) 5 | library(ggplot2) 6 | 7 | # Pre 67 borders 8 | isr <- readRDS("data/maps/00_israel_0_sf.rds") 9 | 10 | # Error requesting to set crs from old version 11 | isr <- st_set_crs(isr, st_crs(isr)) 12 | 13 | ggplot()+ 14 | geom_sf(data = st_as_sf(isr)) 15 | 16 | # ggsave("2021/messing-around/israelpre67.png") 17 | 18 | # Full map 19 | isrfull <- read_sf("data/maps/isr-full/israel_borders.shp") 20 | 21 | ggplot(isrfull)+ 22 | geom_sf() 23 | 24 | # ggsave("2021/messing-around/israel.png") 25 | 26 | # Tel Aviv 27 | tel_aviv_file_name <- list.files(pattern =".Aviv.+\\.shp$", recursive = TRUE) 28 | # I use the file for different projects and reference it several times from a specific folder 29 | tel_aviv_file <- read_sf(paste0(tel_aviv_file_name)) 30 | 31 | 32 | # So Tel-aviv didn't have any crs, but we can see it's in ITM: 33 | tel_aviv_file <- st_set_crs(tel_aviv_file, 2039) 34 | 35 | # Now convert to WGS 84: 36 | tel_aviv_file <- st_transform(tel_aviv_file, 4326) 37 | 38 | 39 | # tmap attempt ------------------------------------------------------------ 40 | 41 | library(tmap) 42 | 43 | t <- qtm(tel_aviv_file, fill = NA, borders = NULL, title = "Just a quick tmap of Tel-Aviv", style = "cobalt") 44 | 45 | tmap_save(t,"2021/messing-around/telaviv_tmap.png") 46 | 47 | # ggmap ------------------------------------------------------------------- 48 | library(ggmap) 49 | 50 | telavivggmap <- get_googlemap(center = "tel aviv, israel", zoom = 12) 51 | 52 | ggmap(telavivggmap) 53 | 54 | # ggsave("2021/messing-around/ggmap.png") 55 | 56 | # Again, this time add an sf object 57 | ggmap(telavivggmap)+ 58 | # Adding sf to ggmap, inherift.aes = FALSE 59 | geom_sf(data = tel_aviv_file, inherit.aes = FALSE, fill = NA) 60 | 61 | # ggsave("2021/messing-around/ggmap_polygon.png") 62 | 63 | 64 | # And again, this time removing labels 65 | telavivggmapclean <- get_googlemap(center = "tel aviv, israel", zoom = 12, style=c(feature="all",element="labels",visibility="off")) 66 | 67 | ggmap(telavivggmapclean)+ 68 | # Adding sf to ggmap, inherift.aes = FALSE 69 | geom_sf(data = tel_aviv_file, inherit.aes = FALSE, fill = NA)+ 70 | theme_void() 71 | 72 | # ggsave("2021/messing-around/ggmap_polygon_clean.png") 73 | 74 | 75 | # Leaflet ----------------------------------------------------------------- 76 | 77 | 78 | library(leaflet) 79 | library(magrittr) 80 | m <- leaflet() %>% 81 | addTiles() %>% 82 | addPolygons(data = tel_aviv_file) 83 | 84 | # mapview::mapshot(m, file = "2021/messing-around/leaflet.png") 85 | 86 | 87 | # Osm data ---------------------------------------------------------------- 88 | library(osmdata) 89 | 90 | opq(st_bbox(tel_aviv_file)) 91 | 92 | dat <- opq(bbox = st_bbox(tel_aviv_file)) %>% 93 | # add_osm_feature(key = 'height') %>% 94 | add_osm_feature(key = "busway") %>% 95 | osmdata_sf() 96 | 97 | q <- opq(st_bbox(tel_aviv_file)) %>% 98 | add_osm_feature(key = 'highway') %>% 99 | osmdata_sf() 100 | 101 | ggplot()+ 102 | # geom_sf(data = st_geometry(q$osm_lines), color = "red")+ 103 | geom_sf(data = st_geometry(q$osm_points), alpha = 0.1) 104 | 105 | ?overline 106 | library(ggplot2) 107 | plot(dat) 108 | available_features() 109 | 110 | 111 | 112 | # stplanr and osrm -------------------------------------------------------- 113 | library(stplanr) 114 | library(osrm) 115 | 116 | trip <- route( 117 | from = st_coordinates(st_sample(tel_aviv_file, size = 1)), 118 | to = st_coordinates(st_sample(tel_aviv_file, size = 1)), 119 | route_fun = osrmRoute, 120 | returnclass = "sf", 121 | osrm.profile = "car" 122 | ) 123 | 124 | mapview::mapview(trip, color = "cyan") 125 | 126 | 127 | 128 | # Buffer zone ------------------------------------------------------------- 129 | 130 | # Dizingof center as a point 131 | # dizcenter <- st_transform(st_sfc(st_point(c(34.774225, 32.077915)), crs = 4326), crs = 2039) 132 | 133 | # 1 Km radius around it 134 | # dizcenter1km <- st_transform(st_buffer(dizcenter, dist = units::set_units(2, "km")), crs = 4326) 135 | 136 | 137 | # st_transform(st_buffer(st_transform(st_as_sf(loc, coords = c("longitude", "latitude"), crs = 4326), 2039), dist = set_units(8, "km")), crs = 4326) 138 | 139 | # lines intersecting within our buffer 140 | # datcomplete <- st_intersection(tel_aviv_file, dat) 141 | 142 | # So Tel-aviv didn't have any crs, but we can see it's in ITM: 143 | tel_aviv_file <- st_set_crs(tel_aviv_file, 2039) 144 | 145 | # Now convert to WGS 84: 146 | tel_aviv_file <- st_transform(tel_aviv_file, 4326) 147 | 148 | 149 | # Extract streets in Tel-Aviv near the Diz center 150 | # streets <- opq(bbox = st_bbox(dizcenter1km)) %>% 151 | # add_osm_feature(key = "highway", value = c("motorway","primary", 152 | # "secondary", "tertiary", "residential", 153 | # "service")) %>% 154 | # osmdata_sf() 155 | 156 | 157 | 158 | # Bus routes -------------------------------------------------------------- 159 | 160 | 161 | # Check out more at 162 | # https://transitfeeds.com/p/ministry-of-transport-and-road-safety/820 163 | 164 | routes 165 | routes <- fread("2021/data/stop_times.txt") 166 | setkey(routes, "stop_id") 167 | setkey(dat, "stop_id") 168 | 169 | dat[routes, on = "stop_id", nomatch=0][trip_id == "44092626_041121",.(mean(arrival_time)), by = trip_id] 170 | 171 | 172 | # elevater ---------------------------------------------------------------- 173 | 174 | 175 | 176 | 177 | isrraster <- get_elev_raster(locations = isrfull, z = 9, clip = "locations") 178 | 179 | elevation_data <- as.data.frame(isrraster, xy = TRUE) 180 | 181 | 182 | colnames(elevation_data)[3] <- "elevation" 183 | # remove rows of data frame with one or more NA's,using complete.cases 184 | elevation_data <- elevation_data[complete.cases(elevation_data), ] 185 | 186 | ggplot() + 187 | geom_point(data = elevation_data, aes(x = x, y = y, color = elevation)) + 188 | scale_color_gradient(low = "white", high = "black")+ 189 | coord_sf() + 190 | theme_void() 191 | 192 | -------------------------------------------------------------------------------- /2022/01_points/01_points.R: -------------------------------------------------------------------------------- 1 | library(readr) 2 | library(sf) 3 | library(dplyr) 4 | library(systemfonts) 5 | library(snapbox) 6 | library(ggplot2) 7 | library(ggsflabel) 8 | 9 | rehovot_path <- list.files('../data/maps/judicial/', recursive = T, pattern = 'gv_Rehovot_2016_plt\\.shp$') 10 | 11 | # taken from June Choe's blog 12 | fa_solid_path <- system_fonts() %>% 13 | filter(family == "Font Awesome 6 Free", style == "Solid") %>% 14 | pull(path) 15 | 16 | systemfonts::register_font( 17 | name = "Font Awesome 6 Free Solid", 18 | plain = fa_solid_path 19 | ) 20 | 21 | rehovot_sf <- st_read(paste0('../data/maps/judicial/', rehovot_path)) %>% 22 | st_transform(crs = 4326) # %>% 23 | # remove the holes (combine Gibton) 24 | # sfheaders::sf_remove_holes() 25 | 26 | 27 | polling_stations <- read_csv('01_points/polling_station_rehovot.csv') %>% 28 | filter(lon <= 34.85) %>% 29 | select(address:lon) %>% 30 | mutate(is_voting_location = ifelse(lat == 31.89650869, 'Yes', 'no')) %>% 31 | st_as_sf(coords = c('lon', 'lat'), crs = 4326) %>% 32 | mutate(label = 'vote-yea') 33 | 34 | # Great tip to cutout part of the map, I just used it as a mask: 35 | # https://stackoverflow.com/questions/69126928/hide-area-outside-of-area-of-interest-in-ggspatial 36 | rehovot_mask <- st_buffer(rehovot_sf, units::as_units(5.5, "km")) %>% 37 | st_difference(rehovot_sf) 38 | 39 | # Plot -------------------------------------------------------------------- 40 | p <- ggplot() + 41 | (layer_mapbox(st_bbox(rehovot_sf, crs = 4326) + c(-0.01,-0.01,0.01, 0.01), 42 | scale_ratio = 0.6, map_style = mapbox_gallery_frank())) 43 | 44 | p + 45 | geom_sf(data = rehovot_sf, inherit.aes = F,fill = NA, color = 'black', lwd = 1) + 46 | geom_sf(data = rehovot_mask, inherit.aes = F,fill = 'white', color = NA, alpha = 0.65) + 47 | geom_sf_text(data = polling_stations, aes(label = label, color = is_voting_location ), 48 | inherit.aes = F, family = 'Font Awesome 6 Free Solid', size = 3, show.legend = FALSE)+ 49 | scale_color_manual(values = c('Yes' = '#00008b', 'no' = 'gray55'))+ 50 | coord_sf()+ 51 | theme_void() + 52 | theme( 53 | panel.background =element_rect(fill = 'white', color = NA), 54 | plot.background =element_rect(fill = 'white', color = NA) 55 | ) 56 | 57 | ggsave('test.png',width = 13, height = 13, dpi = 500) 58 | 59 | 60 | img = magick::image_read('test.png') 61 | img_cropped = magick::image_trim(img) # cutout extra white space 62 | 63 | # img2 = magick::image_crop(img, '5000x3500+750+1250') 64 | 65 | magick::image_write(img_cropped, '01_points/map.png') 66 | -------------------------------------------------------------------------------- /2022/01_points/01_polling_locations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/01_points/01_polling_locations.png -------------------------------------------------------------------------------- /2022/01_points/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/01_points/map.png -------------------------------------------------------------------------------- /2022/01_points/polling_address_to_geo_files/libs/bootstrap/bootstrap-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/01_points/polling_address_to_geo_files/libs/bootstrap/bootstrap-icons.woff -------------------------------------------------------------------------------- /2022/01_points/polling_address_to_geo_files/libs/clipboard/clipboard.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * clipboard.js v2.0.10 3 | * https://clipboardjs.com/ 4 | * 5 | * Licensed MIT © Zeno Rocha 6 | */ 7 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1.anchorjs-link,.anchorjs-link:focus{opacity:1}",u.sheet.cssRules.length),u.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",u.sheet.cssRules.length),u.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',u.sheet.cssRules.length)),u=document.querySelectorAll("[id]"),t=[].map.call(u,function(A){return A.id}),i=0;i\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); 9 | // @license-end -------------------------------------------------------------------------------- /2022/01_points/polling_address_to_geo_files/libs/quarto-html/quarto-syntax-highlighting.css: -------------------------------------------------------------------------------- 1 | /* quarto syntax highlight colors */ 2 | :root { 3 | --quarto-hl-ot-color: #003B4F; 4 | --quarto-hl-at-color: #657422; 5 | --quarto-hl-ss-color: #20794D; 6 | --quarto-hl-an-color: #5E5E5E; 7 | --quarto-hl-fu-color: #4758AB; 8 | --quarto-hl-st-color: #20794D; 9 | --quarto-hl-cf-color: #003B4F; 10 | --quarto-hl-op-color: #5E5E5E; 11 | --quarto-hl-er-color: #AD0000; 12 | --quarto-hl-bn-color: #AD0000; 13 | --quarto-hl-al-color: #AD0000; 14 | --quarto-hl-va-color: #111111; 15 | --quarto-hl-bu-color: inherit; 16 | --quarto-hl-ex-color: inherit; 17 | --quarto-hl-pp-color: #AD0000; 18 | --quarto-hl-in-color: #5E5E5E; 19 | --quarto-hl-vs-color: #20794D; 20 | --quarto-hl-wa-color: #5E5E5E; 21 | --quarto-hl-do-color: #5E5E5E; 22 | --quarto-hl-im-color: #00769E; 23 | --quarto-hl-ch-color: #20794D; 24 | --quarto-hl-dt-color: #AD0000; 25 | --quarto-hl-fl-color: #AD0000; 26 | --quarto-hl-co-color: #5E5E5E; 27 | --quarto-hl-cv-color: #5E5E5E; 28 | --quarto-hl-cn-color: #8f5902; 29 | --quarto-hl-sc-color: #5E5E5E; 30 | --quarto-hl-dv-color: #AD0000; 31 | --quarto-hl-kw-color: #003B4F; 32 | } 33 | 34 | /* other quarto variables */ 35 | :root { 36 | --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 37 | } 38 | 39 | pre > code.sourceCode > span { 40 | color: #003B4F; 41 | } 42 | 43 | code span { 44 | color: #003B4F; 45 | } 46 | 47 | code.sourceCode > span { 48 | color: #003B4F; 49 | } 50 | 51 | div.sourceCode, 52 | div.sourceCode pre.sourceCode { 53 | color: #003B4F; 54 | } 55 | 56 | code span.ot { 57 | color: #003B4F; 58 | } 59 | 60 | code span.at { 61 | color: #657422; 62 | } 63 | 64 | code span.ss { 65 | color: #20794D; 66 | } 67 | 68 | code span.an { 69 | color: #5E5E5E; 70 | } 71 | 72 | code span.fu { 73 | color: #4758AB; 74 | } 75 | 76 | code span.st { 77 | color: #20794D; 78 | } 79 | 80 | code span.cf { 81 | color: #003B4F; 82 | } 83 | 84 | code span.op { 85 | color: #5E5E5E; 86 | } 87 | 88 | code span.er { 89 | color: #AD0000; 90 | } 91 | 92 | code span.bn { 93 | color: #AD0000; 94 | } 95 | 96 | code span.al { 97 | color: #AD0000; 98 | } 99 | 100 | code span.va { 101 | color: #111111; 102 | } 103 | 104 | code span.pp { 105 | color: #AD0000; 106 | } 107 | 108 | code span.in { 109 | color: #5E5E5E; 110 | } 111 | 112 | code span.vs { 113 | color: #20794D; 114 | } 115 | 116 | code span.wa { 117 | color: #5E5E5E; 118 | font-style: italic; 119 | } 120 | 121 | code span.do { 122 | color: #5E5E5E; 123 | font-style: italic; 124 | } 125 | 126 | code span.im { 127 | color: #00769E; 128 | } 129 | 130 | code span.ch { 131 | color: #20794D; 132 | } 133 | 134 | code span.dt { 135 | color: #AD0000; 136 | } 137 | 138 | code span.fl { 139 | color: #AD0000; 140 | } 141 | 142 | code span.co { 143 | color: #5E5E5E; 144 | } 145 | 146 | code span.cv { 147 | color: #5E5E5E; 148 | font-style: italic; 149 | } 150 | 151 | code span.cn { 152 | color: #8f5902; 153 | } 154 | 155 | code span.sc { 156 | color: #5E5E5E; 157 | } 158 | 159 | code span.dv { 160 | color: #AD0000; 161 | } 162 | 163 | code span.kw { 164 | color: #003B4F; 165 | } 166 | 167 | .prevent-inlining { 168 | content: ".tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} -------------------------------------------------------------------------------- /2022/01_points/polling_station_rehovot.csv: -------------------------------------------------------------------------------- 1 | ,address,lat,lon 2 | ?,"??""? ????",31.8927303,34.7769436 3 | 0,"???""? ??? ?????? ??? (??? ????",31.8945265,34.7770918 4 | 0,"??""? ?""? ????",31.9021923,34.8252074 5 | 0,"??""? ?? ????",31.8852272,34.7862129 6 | 0,"????? ???? ??? ????""? (?????)",31.88723196,34.78589572 7 | 0,"???""? ?????? - ???? ?????",31.899885,34.799526 8 | 0,"??""? ???????",31.9006595,34.7997207 9 | 0,"???""? ??""? ????",31.9229061,34.8663035 10 | 0,"??""? ???? ?'",31.8917685,34.7995722 11 | 0,"??""? ???? ?",31.8917685,34.7995722 12 | 0,"??""? ???",31.89704658,34.80304551 13 | 0,"??""? ????? ???",31.8941148,34.805065 14 | 0,????? ??????? ????? ??????,31.8921107,34.80779 15 | 0,"??""? ?? ???",31.8895092,34.8089408 16 | 0,"????? ???? ""????""",31.8953369,34.8148519 17 | 0,"??""? ????",31.8981053,34.8154966 18 | 0,"??""? ???? ???",31.9034937,34.8153708 19 | 0,"??""? ????????",31.8964965,34.8154448 20 | 0,"??""? ??""? ???????",31.9002367,34.818781 21 | 0,??? ?????? ??? ??????,31.89650869,34.82489543 22 | 0,"??""? ????? ???? ??""? ??????",31.8920581,34.8190983 23 | 0,"???""? ???? ????",31.8905515,34.8249087 24 | 0,"??""? ???????",31.8816982,34.8196295 25 | 0,"??""? ???? ????-????",31.8839238,34.8172026 26 | 0,"??? ?""? ????-????? ???? ??????",31.8824356,34.8156686 27 | 0,"??""? ?????",31.8767152,34.8141885 28 | 0,"??""? ?? ??????",31.8785607,34.8159989 29 | 0,"???""? ???? ??? (??????)",31.90068024,34.81997323 30 | 0,"???""? ????????",31.885044,34.8026166 31 | 0,???? ??????,31.883297,34.808894 32 | 0,"??""? ?????? ???",31.8833207,34.8089712 33 | 0,?????? ???????? ???? - ??????,31.8822529,34.8287707 34 | 0,???? ??????-???? ????,31.8825048,34.8193654 35 | 0,"??""? ???""?",31.88924898,34.8239414 36 | 0,???? ????? ?????? (???),31.8896029,34.8308089 37 | 0,"??""? ???? ??????",31.8864741,34.8063198 38 | 0,"??""? ??""? ????? ?????",31.8895773,34.8236509 39 | 0,"??""? ???",31.88671967,34.8272474 40 | 0,"???""? ?????? ?????",31.8927419,34.7821437 41 | 0,??? ???? ????,31.87892544,34.81209852 42 | 0,??? ???? ????,31.9048138,34.8242721 43 | 0,"??""? ????? ????",31.9012034,34.8223669 44 | 0,"??""? ????",31.88354574,34.7912934 45 | 0,???? ?????? ????????,31.8918645,34.7825402 46 | -------------------------------------------------------------------------------- /2022/01_points/rehovot_polls.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/01_points/rehovot_polls.xlsx -------------------------------------------------------------------------------- /2022/02_lines/lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/02_lines/lines.png -------------------------------------------------------------------------------- /2022/02_lines/lines_files/Proj4Leaflet-1.0.1/proj4leaflet.js: -------------------------------------------------------------------------------- 1 | (function (factory) { 2 | var L, proj4; 3 | if (typeof define === 'function' && define.amd) { 4 | // AMD 5 | define(['leaflet', 'proj4'], factory); 6 | } else if (typeof module === 'object' && typeof module.exports === "object") { 7 | // Node/CommonJS 8 | L = require('leaflet'); 9 | proj4 = require('proj4'); 10 | module.exports = factory(L, proj4); 11 | } else { 12 | // Browser globals 13 | if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined') 14 | throw 'Leaflet and proj4 must be loaded first'; 15 | factory(window.L, window.proj4); 16 | } 17 | }(function (L, proj4) { 18 | if (proj4.__esModule && proj4.default) { 19 | // If proj4 was bundled as an ES6 module, unwrap it to get 20 | // to the actual main proj4 object. 21 | // See discussion in https://github.com/kartena/Proj4Leaflet/pull/147 22 | proj4 = proj4.default; 23 | } 24 | 25 | L.Proj = {}; 26 | 27 | L.Proj._isProj4Obj = function(a) { 28 | return (typeof a.inverse !== 'undefined' && 29 | typeof a.forward !== 'undefined'); 30 | }; 31 | 32 | L.Proj.Projection = L.Class.extend({ 33 | initialize: function(code, def, bounds) { 34 | var isP4 = L.Proj._isProj4Obj(code); 35 | this._proj = isP4 ? code : this._projFromCodeDef(code, def); 36 | this.bounds = isP4 ? def : bounds; 37 | }, 38 | 39 | project: function (latlng) { 40 | var point = this._proj.forward([latlng.lng, latlng.lat]); 41 | return new L.Point(point[0], point[1]); 42 | }, 43 | 44 | unproject: function (point, unbounded) { 45 | var point2 = this._proj.inverse([point.x, point.y]); 46 | return new L.LatLng(point2[1], point2[0], unbounded); 47 | }, 48 | 49 | _projFromCodeDef: function(code, def) { 50 | if (def) { 51 | proj4.defs(code, def); 52 | } else if (proj4.defs[code] === undefined) { 53 | var urn = code.split(':'); 54 | if (urn.length > 3) { 55 | code = urn[urn.length - 3] + ':' + urn[urn.length - 1]; 56 | } 57 | if (proj4.defs[code] === undefined) { 58 | throw 'No projection definition for code ' + code; 59 | } 60 | } 61 | 62 | return proj4(code); 63 | } 64 | }); 65 | 66 | L.Proj.CRS = L.Class.extend({ 67 | includes: L.CRS, 68 | 69 | options: { 70 | transformation: new L.Transformation(1, 0, -1, 0) 71 | }, 72 | 73 | initialize: function(a, b, c) { 74 | var code, 75 | proj, 76 | def, 77 | options; 78 | 79 | if (L.Proj._isProj4Obj(a)) { 80 | proj = a; 81 | code = proj.srsCode; 82 | options = b || {}; 83 | 84 | this.projection = new L.Proj.Projection(proj, options.bounds); 85 | } else { 86 | code = a; 87 | def = b; 88 | options = c || {}; 89 | this.projection = new L.Proj.Projection(code, def, options.bounds); 90 | } 91 | 92 | L.Util.setOptions(this, options); 93 | this.code = code; 94 | this.transformation = this.options.transformation; 95 | 96 | if (this.options.origin) { 97 | this.transformation = 98 | new L.Transformation(1, -this.options.origin[0], 99 | -1, this.options.origin[1]); 100 | } 101 | 102 | if (this.options.scales) { 103 | this._scales = this.options.scales; 104 | } else if (this.options.resolutions) { 105 | this._scales = []; 106 | for (var i = this.options.resolutions.length - 1; i >= 0; i--) { 107 | if (this.options.resolutions[i]) { 108 | this._scales[i] = 1 / this.options.resolutions[i]; 109 | } 110 | } 111 | } 112 | 113 | this.infinite = !this.options.bounds; 114 | 115 | }, 116 | 117 | scale: function(zoom) { 118 | var iZoom = Math.floor(zoom), 119 | baseScale, 120 | nextScale, 121 | scaleDiff, 122 | zDiff; 123 | if (zoom === iZoom) { 124 | return this._scales[zoom]; 125 | } else { 126 | // Non-integer zoom, interpolate 127 | baseScale = this._scales[iZoom]; 128 | nextScale = this._scales[iZoom + 1]; 129 | scaleDiff = nextScale - baseScale; 130 | zDiff = (zoom - iZoom); 131 | return baseScale + scaleDiff * zDiff; 132 | } 133 | }, 134 | 135 | zoom: function(scale) { 136 | // Find closest number in this._scales, down 137 | var downScale = this._closestElement(this._scales, scale), 138 | downZoom = this._scales.indexOf(downScale), 139 | nextScale, 140 | nextZoom, 141 | scaleDiff; 142 | // Check if scale is downScale => return array index 143 | if (scale === downScale) { 144 | return downZoom; 145 | } 146 | if (downScale === undefined) { 147 | return -Infinity; 148 | } 149 | // Interpolate 150 | nextZoom = downZoom + 1; 151 | nextScale = this._scales[nextZoom]; 152 | if (nextScale === undefined) { 153 | return Infinity; 154 | } 155 | scaleDiff = nextScale - downScale; 156 | return (scale - downScale) / scaleDiff + downZoom; 157 | }, 158 | 159 | distance: L.CRS.Earth.distance, 160 | 161 | R: L.CRS.Earth.R, 162 | 163 | /* Get the closest lowest element in an array */ 164 | _closestElement: function(array, element) { 165 | var low; 166 | for (var i = array.length; i--;) { 167 | if (array[i] <= element && (low === undefined || low < array[i])) { 168 | low = array[i]; 169 | } 170 | } 171 | return low; 172 | } 173 | }); 174 | 175 | L.Proj.GeoJSON = L.GeoJSON.extend({ 176 | initialize: function(geojson, options) { 177 | this._callLevel = 0; 178 | L.GeoJSON.prototype.initialize.call(this, geojson, options); 179 | }, 180 | 181 | addData: function(geojson) { 182 | var crs; 183 | 184 | if (geojson) { 185 | if (geojson.crs && geojson.crs.type === 'name') { 186 | crs = new L.Proj.CRS(geojson.crs.properties.name); 187 | } else if (geojson.crs && geojson.crs.type) { 188 | crs = new L.Proj.CRS(geojson.crs.type + ':' + geojson.crs.properties.code); 189 | } 190 | 191 | if (crs !== undefined) { 192 | this.options.coordsToLatLng = function(coords) { 193 | var point = L.point(coords[0], coords[1]); 194 | return crs.projection.unproject(point); 195 | }; 196 | } 197 | } 198 | 199 | // Base class' addData might call us recursively, but 200 | // CRS shouldn't be cleared in that case, since CRS applies 201 | // to the whole GeoJSON, inluding sub-features. 202 | this._callLevel++; 203 | try { 204 | L.GeoJSON.prototype.addData.call(this, geojson); 205 | } finally { 206 | this._callLevel--; 207 | if (this._callLevel === 0) { 208 | delete this.options.coordsToLatLng; 209 | } 210 | } 211 | } 212 | }); 213 | 214 | L.Proj.geoJson = function(geojson, options) { 215 | return new L.Proj.GeoJSON(geojson, options); 216 | }; 217 | 218 | L.Proj.ImageOverlay = L.ImageOverlay.extend({ 219 | initialize: function (url, bounds, options) { 220 | L.ImageOverlay.prototype.initialize.call(this, url, null, options); 221 | this._projectedBounds = bounds; 222 | }, 223 | 224 | // Danger ahead: Overriding internal methods in Leaflet. 225 | // Decided to do this rather than making a copy of L.ImageOverlay 226 | // and doing very tiny modifications to it. 227 | // Future will tell if this was wise or not. 228 | _animateZoom: function (event) { 229 | var scale = this._map.getZoomScale(event.zoom); 230 | var northWest = L.point(this._projectedBounds.min.x, this._projectedBounds.max.y); 231 | var offset = this._projectedToNewLayerPoint(northWest, event.zoom, event.center); 232 | 233 | L.DomUtil.setTransform(this._image, offset, scale); 234 | }, 235 | 236 | _reset: function () { 237 | var zoom = this._map.getZoom(); 238 | var pixelOrigin = this._map.getPixelOrigin(); 239 | var bounds = L.bounds( 240 | this._transform(this._projectedBounds.min, zoom)._subtract(pixelOrigin), 241 | this._transform(this._projectedBounds.max, zoom)._subtract(pixelOrigin) 242 | ); 243 | var size = bounds.getSize(); 244 | 245 | L.DomUtil.setPosition(this._image, bounds.min); 246 | this._image.style.width = size.x + 'px'; 247 | this._image.style.height = size.y + 'px'; 248 | }, 249 | 250 | _projectedToNewLayerPoint: function (point, zoom, center) { 251 | var viewHalf = this._map.getSize()._divideBy(2); 252 | var newTopLeft = this._map.project(center, zoom)._subtract(viewHalf)._round(); 253 | var topLeft = newTopLeft.add(this._map._getMapPanePos()); 254 | 255 | return this._transform(point, zoom)._subtract(topLeft); 256 | }, 257 | 258 | _transform: function (point, zoom) { 259 | var crs = this._map.options.crs; 260 | var transformation = crs.transformation; 261 | var scale = crs.scale(zoom); 262 | 263 | return transformation.transform(point, scale); 264 | } 265 | }); 266 | 267 | L.Proj.imageOverlay = function (url, bounds, options) { 268 | return new L.Proj.ImageOverlay(url, bounds, options); 269 | }; 270 | 271 | return L.Proj; 272 | })); 273 | -------------------------------------------------------------------------------- /2022/02_lines/lines_files/leaflet-1.3.1/images/layers-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/02_lines/lines_files/leaflet-1.3.1/images/layers-2x.png -------------------------------------------------------------------------------- /2022/02_lines/lines_files/leaflet-1.3.1/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/02_lines/lines_files/leaflet-1.3.1/images/layers.png -------------------------------------------------------------------------------- /2022/02_lines/lines_files/leaflet-1.3.1/images/marker-icon-2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/02_lines/lines_files/leaflet-1.3.1/images/marker-icon-2x.png -------------------------------------------------------------------------------- /2022/02_lines/lines_files/leaflet-1.3.1/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/02_lines/lines_files/leaflet-1.3.1/images/marker-icon.png -------------------------------------------------------------------------------- /2022/02_lines/lines_files/leaflet-1.3.1/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/02_lines/lines_files/leaflet-1.3.1/images/marker-shadow.png -------------------------------------------------------------------------------- /2022/02_lines/lines_files/leaflet-providers-plugin-2.1.1/leaflet-providers-plugin.js: -------------------------------------------------------------------------------- 1 | LeafletWidget.methods.addProviderTiles = function(provider, layerId, group, options) { 2 | this.layerManager.addLayer(L.tileLayer.provider(provider, options), "tile", layerId, group); 3 | }; 4 | -------------------------------------------------------------------------------- /2022/02_lines/lines_files/leafletfix-1.0.0/leafletfix.css: -------------------------------------------------------------------------------- 1 | /* Work around CSS properties introduced on img by bootstrap */ 2 | img.leaflet-tile { 3 | padding: 0; 4 | margin: 0; 5 | border-radius: 0; 6 | border: none; 7 | } 8 | .info { 9 | padding: 6px 8px; 10 | font: 14px/16px Arial, Helvetica, sans-serif; 11 | background: white; 12 | background: rgba(255,255,255,0.8); 13 | box-shadow: 0 0 15px rgba(0,0,0,0.2); 14 | border-radius: 5px; 15 | } 16 | .legend { 17 | line-height: 18px; 18 | color: #555; 19 | } 20 | .legend svg text { 21 | fill: #555; 22 | } 23 | .legend svg line { 24 | stroke: #555; 25 | } 26 | .legend i { 27 | width: 18px; 28 | height: 18px; 29 | margin-right: 4px; 30 | opacity: 0.7; 31 | display: inline-block; 32 | vertical-align: top; 33 | /*For IE 7*/ 34 | zoom: 1; 35 | *display: inline; 36 | } 37 | -------------------------------------------------------------------------------- /2022/02_lines/lines_files/rstudio_leaflet-1.3.1/images/1px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/02_lines/lines_files/rstudio_leaflet-1.3.1/images/1px.png -------------------------------------------------------------------------------- /2022/02_lines/lines_files/rstudio_leaflet-1.3.1/rstudio_leaflet.css: -------------------------------------------------------------------------------- 1 | .leaflet-tooltip.leaflet-tooltip-text-only, 2 | .leaflet-tooltip.leaflet-tooltip-text-only:before, 3 | .leaflet-tooltip.leaflet-tooltip-text-only:after { 4 | background: none; 5 | border: none; 6 | box-shadow: none; 7 | } 8 | 9 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-left { 10 | margin-left: 5px; 11 | } 12 | 13 | .leaflet-tooltip.leaflet-tooltip-text-only.leaflet-tooltip-right { 14 | margin-left: -5px; 15 | } 16 | 17 | .leaflet-tooltip:after { 18 | border-right: 6px solid transparent; 19 | /* right: -16px; */ 20 | } 21 | 22 | .leaflet-popup-pane .leaflet-popup-tip-container { 23 | /* when the tooltip container is clicked, it is closed */ 24 | pointer-events: all; 25 | /* tooltips should display the "hand" icon, just like .leaflet-interactive*/ 26 | cursor: pointer; 27 | } 28 | 29 | /* have the widget be displayed in the right 'layer' */ 30 | .leaflet-map-pane { 31 | z-index: auto; 32 | } 33 | 34 | /* Add missing rule from leaflet for img. 35 | This complete existing leaflet.css. 36 | Fix for https://github.com/rstudio/rmarkdown/issues/1949 */ 37 | .leaflet-container .leaflet-right-pane img, 38 | .leaflet-container .leaflet-left-pane img { 39 | max-width: none !important; 40 | max-height: none !important; 41 | } 42 | -------------------------------------------------------------------------------- /2022/02_lines/routes.R: -------------------------------------------------------------------------------- 1 | # Code from Alexandra Kapp day 9: https://alexandrakapp.github.io/30daymapchallenge/index.html 2 | # Check it out^^ 3 | 4 | library(sf) 5 | library(dplyr) 6 | library(osrm) 7 | library(stplanr) 8 | library(leaflet) 9 | library(htmltools) 10 | library(htmlwidgets) 11 | library(webshot) 12 | 13 | rehovot_path <- list.files('../data/maps/judicial/', recursive = T, pattern = 'gv_Rehovot_2016_plt\\.shp$') 14 | 15 | rehovot_sf <- st_read(paste0('../data/maps/judicial/', rehovot_path)) %>% 16 | st_transform(crs = 4326)# %>% 17 | # remove the holes (combine Gibton) 18 | # sfheaders::sf_remove_holes() 19 | 20 | 21 | routes <- route(from = st_coordinates(st_sample(rehovot_sf, size = 1000)), 22 | to = st_coordinates(st_sample(rehovot_sf, size = 1000)), 23 | route_fun = osrmRoute, 24 | returnclass = "sf") 25 | 26 | routes["count"] <- 1 27 | 28 | overlapping_segments <- overline(routes, attrib = "count") 29 | 30 | p <- leaflet(overlapping_segments) %>% 31 | addProviderTiles(providers$CartoDB.DarkMatter) %>% 32 | addPolylines(weight = overlapping_segments$count / 6, color = "white") %>% 33 | addControl(html = paste(tags$h1(HTML("Major routes
in Rehovot, Israel"), style = "color:white; font-family:Merriweather; font-size: 30pt; padding-left: 12px; line-height: 1.2em;"), 34 | tags$div(HTML("Most commonly traveled roads
from a sample of 1000 routes."), style = "color:white; font-family:Segoe UI; font-size: 15pt; padding-left: 15px; margin-top:-20px")) 35 | , className = "fieldset { 36 | border: 0; 37 | }", position = "topleft") %>% 38 | addControl(html = tags$div(HTML("Adapted from Alexandra Kapp • Data: {stplanr} package • Amit Levinson"), style = "color:#BEBEBE; font-family:Segoe UI; font-size: 10pt; padding-left: 15px;"), className = "fieldset {border: 0;}", position = "bottomleft") 39 | 40 | # Saving a snapshot 41 | saveWidget(p, "02_lines/lines.html") 42 | webshot("02_lines/lines.html", file = "02_lines/lines.png", zoom = 3, vwidth = 1000, vheight = 700, delay = 2) 43 | -------------------------------------------------------------------------------- /2022/03_polygons/all_rides.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/03_polygons/all_rides.rds -------------------------------------------------------------------------------- /2022/03_polygons/area_distribution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/03_polygons/area_distribution.png -------------------------------------------------------------------------------- /2022/03_polygons/area_distribution_updated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/03_polygons/area_distribution_updated.png -------------------------------------------------------------------------------- /2022/03_polygons/bus_stops.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/03_polygons/bus_stops.png -------------------------------------------------------------------------------- /2022/03_polygons/bus_stops_updated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/03_polygons/bus_stops_updated.png -------------------------------------------------------------------------------- /2022/03_polygons/stops_in_rehovot.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/03_polygons/stops_in_rehovot.rds -------------------------------------------------------------------------------- /2022/07_raster/07_raster.R: -------------------------------------------------------------------------------- 1 | # https://rspatialdata.github.io/elevation.html 2 | 3 | library(elevatr) 4 | library(sf) 5 | library(raster) 6 | library(ggplot2) 7 | library(ggtext) 8 | 9 | # Get Israel map for extracting raster layer below, you can also use the {rgeoboundaries} instead 10 | # to get boundaries of a country you're interested in. 11 | isr_map <- readRDS(paste0('../data/maps/00_Israel_0_sf.rds')) 12 | 13 | 14 | # Get elevation data 15 | isrraster <- get_elev_raster(locations = isr_map, z = 10, clip = "locations") 16 | 17 | elevation_data <- as.data.frame(isrraster, xy = TRUE) 18 | colnames(elevation_data)[3] <- "elevation" 19 | elevation_data <- elevation_data[complete.cases(elevation_data), ] 20 | 21 | ggplot() + 22 | geom_raster(data = elevation_data, aes(x = x, y = y, fill = elevation)) + 23 | coord_sf() + 24 | scale_fill_viridis_c(name = "Elevation (meters)" ,option = 'E', labels = scales::comma) + 25 | labs(title = "Elevation in Israel", 26 | x = "Longitude", 27 | y = "Latitude", 28 | caption = 'Data: {elvatar} package & AWS Tiles • Visualization: Amit Grinson') + 29 | theme( 30 | text = element_text(family = "Quicksand", lineheight = 1), 31 | plot.title = element_text(size = 28, family = "Roboto Slab", face = 'bold', hjust = 1), 32 | plot.subtitle = element_text(size = 18, lineheight = 1.1), 33 | plot.caption = element_markdown(hjust = 0, size = 12, color = "gray25"), 34 | axis.text = element_blank(), 35 | axis.title = element_blank(), 36 | legend.title = element_text(size = 12), 37 | legend.text = element_text(size = 10), 38 | # legend.position = 'horizontal', 39 | panel.background = element_rect(fill = "white", color = NA), 40 | plot.background = element_rect(fill = "white", color = NA), 41 | panel.grid = element_blank(), 42 | plot.margin = margin(6,2,6,2,"mm"), 43 | axis.ticks = element_blank() 44 | ) 45 | 46 | ggsave('07_raster/elevation_high_res.png', width = 7, height = 11) 47 | -------------------------------------------------------------------------------- /2022/07_raster/elevation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/07_raster/elevation.png -------------------------------------------------------------------------------- /2022/07_raster/elevation_high_res.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/07_raster/elevation_high_res.png -------------------------------------------------------------------------------- /2022/08_osm/rehovot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/08_osm/rehovot.png -------------------------------------------------------------------------------- /2022/08_osm/rehovot_sf/gv_Rehovot_2016_plt.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/08_osm/rehovot_sf/gv_Rehovot_2016_plt.dbf -------------------------------------------------------------------------------- /2022/08_osm/rehovot_sf/gv_Rehovot_2016_plt.prj: -------------------------------------------------------------------------------- 1 | PROJCS["Israel_TM_Grid",GEOGCS["GCS_Israel",DATUM["D_Israel",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",219529.584],PARAMETER["False_Northing",626907.39],PARAMETER["Central_Meridian",35.20451694444445],PARAMETER["Scale_Factor",1.0000067],PARAMETER["Latitude_Of_Origin",31.73439361111111],UNIT["Meter",1.0]] -------------------------------------------------------------------------------- /2022/08_osm/rehovot_sf/gv_Rehovot_2016_plt.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/08_osm/rehovot_sf/gv_Rehovot_2016_plt.shp -------------------------------------------------------------------------------- /2022/08_osm/rehovot_sf/gv_Rehovot_2016_plt.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/08_osm/rehovot_sf/gv_Rehovot_2016_plt.shx -------------------------------------------------------------------------------- /2022/14_hexagons/14_hexagons.R: -------------------------------------------------------------------------------- 1 | library(sf) 2 | library(dplyr) 3 | library(ggplot2) 4 | library(googleway) 5 | library(purrr) 6 | library(tidyr) 7 | 8 | rehovot_path <- list.files('data/maps/judicial/', recursive = T, pattern = 'gv_Rehovot_2016_plt\\.shp$') 9 | 10 | rehovot_sf <- st_read(paste0('data/maps/judicial/', rehovot_path)) %>% 11 | # st_transform(crs = 4326) %>% 12 | sfheaders::sf_remove_holes() 13 | 14 | home <- st_geometry(st_point(c(34.809366, 31.898025))) %>% 15 | st_set_crs(4326) 16 | 17 | grid_square <- st_make_grid(rehovot_sf, cellsize = 250,square = FALSE) 18 | 19 | 20 | rehovot_grid <- grid_square[st_intersects(grid_square, rehovot_sf, sparse = F) %>% 21 | as.vector()] %>% 22 | st_transform(crs = 4326) %>% 23 | st_as_sf() 24 | 25 | hexagons_to_measure <- rehovot_grid[!st_within(home, rehovot_grid, sparse = F) %>% as.vector(),] 26 | 27 | 28 | 29 | hexagons_centroids <- rehovot_grid %>% 30 | st_centroid() %>% 31 | st_coordinates() %>% 32 | as_tibble() %>% 33 | select(lat = Y, long = X) 34 | 35 | get_distance_info <- function(lat, long, way) { 36 | Sys.sleep(1) 37 | travel_info <- googleway::google_distance(origins = c(31.89803, 34.80937), 38 | destinations = c(lat, long), 39 | mode = way, 40 | key = keyring::key_get('google-key')) 41 | 42 | dat <- travel_info$rows$elements[[1]] %>% 43 | as_tibble() %>% 44 | unnest() %>% 45 | mutate(mode = way, 46 | address = travel_info$destination_addresses, 47 | lat = lat, 48 | long = long) 49 | 50 | return(dat) 51 | } 52 | # 53 | # get_distance_info(31.8975, 34.76228, 'transit') 54 | 55 | 56 | safe_info <- safely(get_distance_info) 57 | 58 | # queried 21:00 59 | # driving_info <- pmap_dfr(list(hexagons_centroids$lat, hexagons_centroids$long, 'driving'), safe_info) 60 | # saveRDS(driving_info, '2022/14_hexagons/driving.rds') 61 | driving <- readRDS('2022/14_hexagons/driving.rds') 62 | ?google_distance 63 | 64 | # biking_info <- pmap_dfr(list(hexagons_centroids$lat, hexagons_centroids$long, 'bicycling'), safe_info) 65 | # saveRDS(biking_info, '2022/14_hexagons/biking.rds') 66 | biking <- readRDS('2022/14_hexagons/biking.rds') 67 | 68 | hexagons_distance <- rbind(biking, driving) %>% 69 | rename(travel_seconds = value1, travel_m = value) %>% 70 | # group_by(lat,long) %>% 71 | pivot_wider(id_cols = c('long', 'lat'), 72 | values_from = c(travel_seconds,travel_m),names_from = 'mode') %>% 73 | mutate(ratio = travel_seconds_bicycling - travel_seconds_driving) %>% 74 | st_as_sf(coords = c('long', 'lat'), crs = 4326) %>% 75 | st_join(x= hexagons_to_measure, y = .) 76 | 77 | limit <- max(abs(hexagons_distance$ratio)) * c(-1, 1) 78 | 79 | ggplot(hexagons_distance) + 80 | geom_sf(aes(fill = ratio))+ 81 | scale_fill_distiller(palette = 'RdBu', limit =limit ) 82 | 83 | hexagons_distance %>% 84 | arrange(ratio) 85 | 86 | pal <- colorNumeric('RdBu',hexagons_distance$ratio) 87 | 88 | library(leaflet) 89 | leaflet(hexagons_distance) %>% 90 | addTiles() %>% 91 | addPolygons(stroke = FALSE, fillOpacity = 0.8, 92 | fillColor = pal(hexagons_distance$ratio)) %>% 93 | addLegend(pal = pal, values = ~ratio) 94 | 95 | 96 | ?colorNumeric 97 | ggplot(aes(fill = ratio)) + 98 | geom_sf(color = NA) 99 | 100 | rehovot_grid %>% 101 | st_as_sf 102 | 103 | rbind(biking, driving) %>% 104 | count(address, sort = T) 105 | rename(travel_seconds = value1, travel_m = value) %>% 106 | st_as_sf(coords = c('long', 'lat'), crs = 4326) %>% 107 | 108 | st_as_sf(coordinates = c('$long', '$lat')) 109 | 110 | driving_info$result$duration %>% as_tibble() 111 | 112 | ?google_distance 113 | 114 | keyring::key_set('google-key') 115 | 116 | test$rows$elements %>% 117 | as.data.frame() 118 | 119 | 120 | 121 | ggmap::has_google_key() 122 | test <- route(from = home, 123 | to = hexagons_centroids[1:3], mode = 'bicycling') 124 | 125 | 126 | 127 | 128 | 129 | grid_centroid <- tibble( 130 | grid = st_geometry(rehovot_grid), 131 | centroid = rehovot_grid %>% st_centroid() 132 | ) 133 | 134 | 135 | tes <- rbind(home, hexagons_centroids %>% head(1)) %>% 136 | as.data.frame() %>% 137 | st_as_sf(crs = 4326) 138 | 139 | routes <- osrm::osrmTrip( 140 | loc = tes, 141 | osrm.profile = 'bike') 142 | 143 | install.packages('googleway') 144 | 145 | bike_route <- osrm::osrmTable(src = home, dst = hexagons_dist %>% filter(is.na(duration)) %>% st_centroid(), 146 | osrm.profile = 'bike' ) 147 | 148 | 149 | test_plot <- data.frame(st_geometry(hexagons_to_measure)) %>% 150 | mutate( 151 | duration = bike_route$durations %>% as.vector() 152 | ) %>% 153 | st_as_sf() 154 | 155 | hexagons_dist %>% filter(is.na(duration)) %>% st_centroid() %>% 156 | ggplot() + 157 | geom_sf() 158 | 159 | dat <- bike_route$destinations %>% 160 | st_as_sf(coords = c('lon', 'lat'), crs = 4326) %>% 161 | mutate(duration = bike_route$durations %>% as.vector()) 162 | 163 | hexagons_dist <- st_join(hexagons_to_measure %>% st_as_sf(), dat) 164 | hexagons_dist%>% 165 | ggplot() + 166 | geom_sf(aes(fill = duration)) 167 | 168 | 169 | class(dat) 170 | class() 171 | ?st_coordinates() 172 | st_ 173 | bike_route$destinations 174 | 175 | plot(hexagons_to_measure) 176 | test_plot 177 | 178 | ggplot(test_plot) + 179 | geom_sf(aes(color = duration)) 180 | 181 | plot(test_plot) 182 | 183 | ggplot() 184 | 185 | ?osrm::osrmTable 186 | routes[[1]][[1]] 187 | 188 | routes 189 | plot(routes) 190 | 191 | ggplot()+ 192 | geom_sf(hexagons_to_measure,mapping = aes(), fill ='red') 193 | geom_sf(home, inherit.aes = F, mapping = aes()) 194 | 195 | pharmacy <- st_read(system.file("gpkg/apotheke.gpkg", package = "osrm"), 196 | quiet = TRUE) 197 | travel_time <- osrmTable(loc = pharmacy) 198 | travel_time$durations[1:5,1:5] 199 | 200 | -------------------------------------------------------------------------------- /2022/14_hexagons/14_hexagons_accidents.R: -------------------------------------------------------------------------------- 1 | library(sf) 2 | library(dplyr) 3 | library(ggplot2) 4 | library(readr) 5 | library(ggtext) 6 | 7 | rehovot_path <- list.files('data/maps/judicial/', recursive = T, pattern = 'gv_Rehovot_2016_plt\\.shp$') 8 | rehovot_sf <- st_read(paste0('data/maps/judicial/', rehovot_path)) %>% 9 | sfheaders::sf_remove_holes() 10 | 11 | grid_square <- st_make_grid(rehovot_sf, cellsize = 500,square = FALSE) 12 | 13 | rehovot_grid <- grid_square[st_intersects(grid_square, rehovot_sf, sparse = F) %>% 14 | as.vector()] %>% 15 | st_transform(crs = 4326) %>% 16 | st_as_sf() %>% 17 | mutate(id = 1:nrow(.)) %>% 18 | rename(geometry = x) 19 | 20 | loc <- read_csv('-2019.csv') 21 | 22 | loc_clean <- loc %>% 23 | filter(!is.na(X) | !is.na(Y)) %>% 24 | st_as_sf(coords = c('X', 'Y'), crs = 2039) 25 | 26 | rehovot_accidents <- loc_clean[st_within(loc_clean, rehovot_sf, sparse = F),] %>% 27 | st_transform(crs = 4326) 28 | 29 | 30 | 31 | 32 | hexagons_with_accidents <- rehovot_grid %>% 33 | mutate(total = lengths(st_intersects(., rehovot_accidents)), 34 | total = ifelse(total == 0, NA, total)) 35 | 36 | ggplot(hexagons_with_accidents) + 37 | geom_sf(aes(fill = total), color = 'gray45', lwd = 0.25) + 38 | scale_fill_gradient(name = '# Accidents', low = '#000000', high = '#FF0000', na.value = 'gray85', 39 | breaks = seq(2,12,4))+ 40 | guides(fill = guide_colorbar(title.position="top", title.hjust = 0.5))+ 41 | labs(title = 'Car Accidents in Rehovot, IL', 42 | subtitle = 'Number of car accidents occurring in 2019 per 500m2', 43 | caption = 'Data: gov.il • Amit Grinson')+ 44 | theme_minimal()+ 45 | theme( 46 | text = element_text(family = "Public Sans"), 47 | plot.title = element_text(size = 28, face = 'bold'), 48 | plot.title.position = "plot", 49 | plot.subtitle = element_markdown(size = 18), 50 | plot.caption = element_markdown(hjust = 1, size = 12, color = "gray35"), 51 | axis.text = element_blank(), 52 | axis.title = element_blank(), 53 | legend.title = element_text(size = 15), 54 | legend.text = element_text(size = 12), 55 | legend.position = 'bottom', 56 | legend.key.height = unit(4, 'mm'), 57 | panel.grid = element_blank(), 58 | plot.margin = margin(6,2,6,2,"mm"), 59 | plot.background = element_rect(fill = 'white', color = NA), 60 | panel.background = element_rect(fill = 'white', color = NA) 61 | ) 62 | 63 | 64 | ggsave('2022/14_hexagons/accidents.png', width = 10, height = 8) 65 | 66 | -------------------------------------------------------------------------------- /2022/14_hexagons/accidents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/14_hexagons/accidents.png -------------------------------------------------------------------------------- /2022/14_hexagons/biking.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/14_hexagons/biking.rds -------------------------------------------------------------------------------- /2022/14_hexagons/driving.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/2022/14_hexagons/driving.rds -------------------------------------------------------------------------------- /30daymapchallenge.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 30daymapchallenge 2 | 3 | ### What's this project all about? 4 | 5 | Taken from the [GitHub page](https://github.com/tjukanovt/30DayMapChallenge) of the project: 6 | 7 | > "The idea is to create (and publish) maps based on different themes on each day of the month using the hashtag #30DayMapChallenge, You can prepare the maps beforehand, but the main idea is to publish maps from specific topics on specific days listed below. Just include a picture of the map when you post to Twitter with the hashtag. You don't have to sign up anywhere to participate. There are no restrictions on the tools, technologies and the data you use in your maps. Doing less than 30 is also fine (and actually doing all 30 is really hard!)..." 8 | 9 | #### How do I see it? 10 | 11 | **I don't get to plot maps that often in my daily work, so I find this challenge a great opportunity in doing so.** I'll try to do as many as possible, and you can find below all of the attempts including links to the code for you to explore. 12 | 13 | Enjoy! 14 | 15 | ## 2020 16 | 17 | ### Day 20 - Population (Animated + static) 18 | 19 | [Link to code](https://github.com/AmitLevinson/30daymapchallenge/blob/main/2020/Code/20_population/population.R) 20 | 21 |

22 | gif of israel map and a cartogram 23 |

24 |
25 | 26 | 27 | 28 | ### Day 08 - Yellow 29 | 30 | [Link to code](https://github.com/AmitLevinson/30daymapchallenge/blob/main/2020/Code/08_yellow/08_yellow.R) 31 | 32 |

33 | Map of light posts in beer-sheva 34 |

35 |
36 | 37 | 38 | 39 | ### Day 07 - Green 40 | 41 | [Link to code](https://github.com/AmitLevinson/30daymapchallenge/blob/main/2020/Code/07_green/07_green.R) 42 | 43 |

44 | Mapping trees in San Francisco 45 |

46 |
47 | 48 | ### Day 03 - Polygon 49 | 50 | [Link to code](https://github.com/AmitLevinson/30daymapchallenge/blob/main/2020/Code/03_Polygons/03_polygons.R) 51 | 52 |

53 | 54 |

55 |
56 | 57 | 58 | 59 | ### Day 02 - Lines 60 | 61 | [Link to code](https://github.com/AmitLevinson/30daymapchallenge/blob/main/2020/Code/02_lines/02_lines.R) 62 | 63 |

64 | 65 |

66 |
67 | 68 | ### Day 01 - Points 69 | 70 | [Link to code](https://github.com/AmitLevinson/30daymapchallenge/blob/main/2020/Code/01_points/01_points.R) 71 | 72 |

73 | 74 |

75 | 76 | Back to top -------------------------------------------------------------------------------- /data/maps/00_Israel_0_sf.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/data/maps/00_Israel_0_sf.rds -------------------------------------------------------------------------------- /data/maps/gadm36_ISR_0_sf.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/data/maps/gadm36_ISR_0_sf.rds -------------------------------------------------------------------------------- /data/maps/gadm36_ISR_0_sp.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/data/maps/gadm36_ISR_0_sp.rds -------------------------------------------------------------------------------- /data/maps/gadm36_ISR_1_sf.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/data/maps/gadm36_ISR_1_sf.rds -------------------------------------------------------------------------------- /data/maps/isr-full/israel_borders.dbf: -------------------------------------------------------------------------------- 1 | o 2 | AWIdN 0 -------------------------------------------------------------------------------- /data/maps/isr-full/israel_borders.prj: -------------------------------------------------------------------------------- 1 | PROJCS["WGS_1984_UTM_Zone_36N",GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",33.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]] -------------------------------------------------------------------------------- /data/maps/isr-full/israel_borders.sbn: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/data/maps/isr-full/israel_borders.sbn -------------------------------------------------------------------------------- /data/maps/isr-full/israel_borders.sbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/data/maps/isr-full/israel_borders.sbx -------------------------------------------------------------------------------- /data/maps/isr-full/israel_borders.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/data/maps/isr-full/israel_borders.shp -------------------------------------------------------------------------------- /data/maps/isr-full/israel_borders.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/data/maps/isr-full/israel_borders.shx -------------------------------------------------------------------------------- /expc.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AmitLevinson/30daymapchallenge/2b65006b1b68ef6364028fe72b324c62ffe8cfe0/expc.csv --------------------------------------------------------------------------------