Hi!

I am Ferdausur Rahman

I tried to plot the map of Bangladesh from .shp file. The file can be found on Google by searching with Bangladesh.shp or Bangladesh shape file. I took the file from DIVA-GIS as .zip file and extracted in my working directory.

Setting Working Directory

wd<- getwd()

Load libraries

sf package is to read shape file and ggplot2 to plot

library(sf)
## Linking to GEOS 3.9.1, GDAL 3.2.1, PROJ 7.2.1
library(ggplot2)

Reading data

The shape file could also be read with st.read() from sf package and readOGR() from rgdal package.

adm0 contains information on the country, country name.

adm0<- read_sf(paste(wd, "BGD_adm/BGD_adm0.shp", sep= "/"))
head(adm0)
## Simple feature collection with 1 feature and 70 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 88.01057 ymin: 20.74111 xmax: 92.67366 ymax: 26.6344
## Geodetic CRS:  WGS 84
## # A tibble: 1 x 71
##    ID_0 ISO   NAME_0     OBJECTID_1 ISO3  NAME_ENGLI NAME_ISO NAME_FAO NAME_LOCAL
##   <dbl> <chr> <chr>           <dbl> <chr> <chr>      <chr>    <chr>    <chr>     
## 1    20 BGD   Bangladesh         23 BGD   Bangladesh BANGLAD~ Banglad~ Bangladesh
## # ... with 62 more variables: NAME_OBSOL <chr>, NAME_VARIA <chr>,
## #   NAME_NONLA <chr>, NAME_FRENC <chr>, NAME_SPANI <chr>, NAME_RUSSI <chr>,
## #   NAME_ARABI <chr>, NAME_CHINE <chr>, WASPARTOF <chr>, CONTAINS <chr>,
## #   SOVEREIGN <chr>, ISO2 <chr>, WWW <chr>, FIPS <chr>, ISON <dbl>,
## #   VALIDFR <chr>, VALIDTO <chr>, POP2000 <dbl>, SQKM <dbl>, POPSQKM <dbl>,
## #   UNREGION1 <chr>, UNREGION2 <chr>, DEVELOPING <dbl>, CIS <dbl>,
## #   Transition <dbl>, OECD <dbl>, WBREGION <chr>, WBINCOME <chr>, ...

adm1 contains information on division.

adm1<- read_sf(paste(wd, "BGD_adm/BGD_adm1.shp", sep= "/"))
head(adm1)
## Simple feature collection with 6 features and 9 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 88.01057 ymin: 20.74111 xmax: 92.67366 ymax: 26.6344
## Geodetic CRS:  WGS 84
## # A tibble: 6 x 10
##    ID_0 ISO   NAME_0      ID_1 NAME_1     TYPE_1 ENGTYPE_1 NL_NAME_1 VARNAME_1  
##   <dbl> <chr> <chr>      <dbl> <chr>      <chr>  <chr>     <chr>     <chr>      
## 1    20 BGD   Bangladesh     1 Barisal    Bibhag Division  <NA>      Bakerganj  
## 2    20 BGD   Bangladesh     2 Chittagong Bibhag Division  <NA>      Chattagram~
## 3    20 BGD   Bangladesh     3 Dhaka      Bibhag Division  <NA>      Daca|Dacca 
## 4    20 BGD   Bangladesh     4 Khulna     Bibhag Division  <NA>      <NA>       
## 5    20 BGD   Bangladesh     5 Rajshahi   Bibhag Division  <NA>      <NA>       
## 6    20 BGD   Bangladesh     6 Rangpur    Bibhag Division  <NA>      <NA>       
## # ... with 1 more variable: geometry <MULTIPOLYGON [°]>

adm2 in on districts of Bangladesh.

adm2<- read_sf(paste(wd, "BGD_adm/BGD_adm2.shp", sep= "/"))
head(adm2)
## Simple feature collection with 6 features and 11 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 89.86407 ymin: 21.73779 xmax: 91.00111 ymax: 23.07116
## Geodetic CRS:  WGS 84
## # A tibble: 6 x 12
##    ID_0 ISO   NAME_0      ID_1 NAME_1   ID_2 NAME_2     TYPE_2 ENGTYPE_2 NL_NAME_2
##   <dbl> <chr> <chr>      <dbl> <chr>   <dbl> <chr>      <chr>  <chr>     <chr>    
## 1    20 BGD   Bangladesh     1 Barisal     1 Barisal    Zila   District  <NA>     
## 2    20 BGD   Bangladesh     1 Barisal     2 Bhola      Zila   District  <NA>     
## 3    20 BGD   Bangladesh     1 Barisal     3 Borgona    Zila   District  <NA>     
## 4    20 BGD   Bangladesh     1 Barisal     4 Jhalakati  Zila   District  <NA>     
## 5    20 BGD   Bangladesh     1 Barisal     5 Patuakhali Zila   District  <NA>     
## 6    20 BGD   Bangladesh     1 Barisal     6 Pirojpur   Zila   District  <NA>     
## # ... with 2 more variables: VARNAME_2 <chr>, geometry <MULTIPOLYGON [°]>

adm3 has previous information and information on upazila.

adm3<- read_sf(paste(wd, "BGD_adm/BGD_adm3.shp", sep= "/"))
head(adm3)
## Simple feature collection with 6 features and 13 fields
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: 90.03049 ymin: 22.45434 xmax: 90.53994 ymax: 23.07116
## Geodetic CRS:  WGS 84
## # A tibble: 6 x 14
##    ID_0 ISO   NAME_0      ID_1 NAME_1   ID_2 NAME_2   ID_3 NAME_3 TYPE_3 ENGTYPE_3
##   <dbl> <chr> <chr>      <dbl> <chr>   <dbl> <chr>   <dbl> <chr>  <chr>  <chr>    
## 1    20 BGD   Bangladesh     1 Barisal     1 Barisal     1 Agail~ Upazi~ Sub-dist~
## 2    20 BGD   Bangladesh     1 Barisal     1 Barisal     2 Babug~ Upazi~ Sub-dist~
## 3    20 BGD   Bangladesh     1 Barisal     1 Barisal     3 Baker~ Upazi~ Sub-dist~
## 4    20 BGD   Bangladesh     1 Barisal     1 Barisal     4 Banar~ Upazi~ Sub-dist~
## 5    20 BGD   Bangladesh     1 Barisal     1 Barisal     5 Baris~ Upazi~ Sub-dist~
## 6    20 BGD   Bangladesh     1 Barisal     1 Barisal     6 Gaurn~ Upazi~ Sub-dist~
## # ... with 3 more variables: NL_NAME_3 <chr>, VARNAME_3 <chr>,
## #   geometry <MULTIPOLYGON [°]>

Plotting the map

If the shape data was read by readOGR(), map could be also be plotted by getting latitude, longitude from tidy() of broom package and then calling geom_polygon() on the file.

A solid map of Bangladesh as adm0 only have country information.

map0<- ggplot(adm0)+
        geom_sf(aes(fill= NAME_0))+
        labs(title = "A solid map of Bangladesh", 
             x= "Longitude", y= "Latitude")+
        theme_classic()+
        theme(legend.title = element_blank())
        
map0

adm1 has divisional distribution on column NAME_1.

map1<- ggplot(adm1)+
        geom_sf(aes(fill= NAME_1))+
        labs(title= "A map of Bangladesh with divisional distribution",
             x= "Longitude", y= "latitude")+
        scale_fill_manual("Divisions",
                          values= c("violet", "blue", "cyan", "green", 
                                    "yellow", "orange", "red"))+
        theme_classic()
map1

A map of Bangladesh on districts

map2 <- ggplot(adm2)+
        geom_sf(aes(fill=NAME_1))+
        labs(title="A map of Bangladesh with district distribution",
             x="Longitude",y="Lattitude")+
        theme_classic()+
        scale_fill_manual("Divisions",
                          values= c("violet", "blue", "cyan", "green", 
                                    "yellow", "orange", "red"))
map2

A map of Bangladesh on Upazila

map3<- ggplot(adm3)+
        geom_sf(aes(fill= NAME_1))+
        labs(title= "A map of Bangladesh with upazila subdivision", 
             x= "Longitude", y= "Latitude")+
        theme_classic()+
        scale_fill_manual("Divisions",
                          values= c("violet", "blue", "cyan", "green", 
                                    "yellow", "orange", "red"))
map3

Adding labels on the map

Labels can be added both as text and labels.

  • Text and label can be added with geom_text() and geom_label() respectively. However, they need x and y coordinates along with the label/ texts.
    Approximate x and y can be taken from plotting the map without label first and then re-plotting with labels and coordinates.
lats<- c(25.800, 24.800, 24.700, 23.600, 23.100, 22.850, 22.500, 21.000)
longs<- c(89.200, 91.600, 89.000, 90.100, 89.400, 91.900, 90.300, 90.800)

label_name<- c("Rangpur", "Sylhet", "Rajshahi", "Dhaka", 
         "Khulna", "Chittagong", "Barishal", "Bay of Bengal")

lab_df<- data.frame(label_name, longs, lats)
map4 <- ggplot(adm2)+
        geom_sf(aes(fill=NAME_1))+
        labs(title="A map of Bangladesh with divisional distribution",
             x="Longitude",y="Lattitude")+
        theme_classic()+
        geom_label(data = lab_df, 
                   aes(x= longs, y= lats, label= label_name), 
                   alpha= 0.4)+
        scale_fill_manual("Divisions", 
                          values= c("violet", "blue", "cyan", "green", 
                                    "yellow", "orange", "red"))
map4

  • Text and labels can be also added with geom_sf_text() and geom_sf_label(). They do not require x and y coordinates for adding label/text.
map5 <- ggplot(adm1)+
        geom_sf(aes(fill=NAME_1))+
        labs(title="A map of Bangladesh with divisional distribution",
             x="Longitude",y="Lattitude")+
        theme_classic()+
        geom_sf_label(aes(label= NAME_1), alpha= 0.4)+
        scale_fill_manual("Divisions", 
                          values= c("violet", "blue", "cyan", "green", 
                                    "yellow", "orange", "red"))

map5
## Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may not
## give correct results for longitude/latitude data

Making fill according to a given variable/ column/ information

Population of Bangladesh is taken from Divisions of Bangladesh Wikipedia page is added to the data

adm1$population<- c(8325666, 29145000, 36433505, 15687759, 
                      18485858, 15787758, 9807000)
map6 <- ggplot(adm1)+
        geom_sf(aes(fill=population))+
        labs(title="A map of Bangladesh with population distribution",
             subtitle = "by divisions",
             x="Longitude",y="Lattitude")+
        theme_classic()+
        geom_sf_text(aes(label= NAME_1), color= "white")

map6
## Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may not
## give correct results for longitude/latitude data

Thank you for reading. Hope this helps you.