Skip to content
ImpactMojo ImpactMojo
Browse Membership
Back to Code Studio
Code Studio · Guided tool course

QGIS: maps for development data

Turn a district table into a map you can put in a report: load openly licensed boundaries, join your survey figures to them by district name, choose how to group the values into colours, write a legend that does not mislead, and export a print layout. QGIS is free. Python cells on this page prepare the table and show what the join and the classification choices do to the same data.

QGIS is desktop software. It does not run on this page, and this page shows no QGIS screenshots or maps, because it cannot produce them. The steps tell you what to click and what to look for. Menu paths follow the QGIS 3.44 user manual. The Python cells build the table you will join, test the join, and compare classification methods on the same numbers. The first Python run downloads the engine once (about 10 MB).
Module 1 of 8

Install QGIS: long-term release or latest

QGIS is a free and open source geographic information system. Its home page says it is "licensed under GNU GPLv2+", and the download page says the software "is, and always will be, available free of charge if downloaded from QGIS.org". The download page asks for an optional donation; you can skip it.

Versions, checked 6 October 2026 on the QGIS download page and road map. The latest release is QGIS 4.2.3, released 25 September 2026. The long-term release (LTR) builds provide QGIS 3.44.15. On 3 October 2026 the project announced that the next LTR is delayed and that it plans to release QGIS 4.4.4 as the LTR on 5 March 2027. Until then, 3.44 is the long-term release.

Which one to choose

The download page says LTR builds "are intended for those who value stability over having the latest features", and "if you are unsure which version is best for you, download the LTR". For a programme team that shares project files, choose the LTR and have everyone use the same one. The menu paths on this page are from the QGIS 3.44 user manual; the 4.x releases may place some items differently.

Module 2 of 8

Layers, the map canvas and coordinate systems

A QGIS project (a .qgz file) holds a list of layers and how each is drawn. The project file stores the path to your data, so keep the project and its data in one folder and move them together.

Coordinate reference systems

Every layer has a coordinate reference system (CRS) that says how its numbers map to places on the earth. DataMeet's boundaries are in WGS84, EPSG:4326 (latitude and longitude in degrees), as their project page states. QGIS shows the project's CRS at the bottom right of the window. For a district choropleth of India, WGS84 is fine to start with; if you measure areas or distances, reproject to a projected CRS first, because degrees are not a unit of length.

Opening the attribute table

Select a layer in the Layers panel and choose Layer ► Open Attribute Table, or right-click it and choose Open Attribute Table, or press F6. Do this every time you load or join something: the table is where mistakes show first.

Module 3 of 8

Load district boundaries

Where to get boundaries, and their licences

District maps go out of date. India has created many districts since the 2011 Census, and the 2011 boundaries do not show them. If your survey uses current districts and your boundaries are from 2011, some of your districts will have no polygon and some polygons will cover two of your districts. Decide which set of boundaries matches your sampling frame before you map anything.

Load the layer

  1. Download the district shapefile from DataMeet. A shapefile is several files with the same name and different extensions (.shp, .shx, .dbf, .prj, sometimes more). Keep them together in one folder; the .shp alone is useless.
  2. In QGIS choose Layer ► Add Layer ► Add Vector Layer… (Ctrl + Shift + V), or open the Data Source Manager with Ctrl + L.
  3. Select the .shp file (or a .geojson file, which is a single file) and click Add.
  4. Open the attribute table (F6). In the DataMeet 2011 district file the fields are DISTRICT, ST_NM (state name), ST_CEN_CD, DT_CEN_CD and censuscode. When we read the file on 6 October 2026 it held 641 districts.
Module 4 of 8

Join a CSV to the boundaries

A choropleth needs one value per district in the boundary layer's attribute table. Your survey figures are in a separate table, so you join them, matching rows by a field the two tables share.

Make the district table

The course files are households.csv (240 households) and districts.csv (10 districts). Illustrative data, invented for teaching The district names are real places; every number is made up, so a map of them says nothing about the real districts. The cell summarises the households to one row per district and prints it as CSV for you to save.

Each district has 24 households. Mean monthly per capita expenditure runs from Rs 2,395.0 in Purnia to Rs 6,757.5 in Kozhikode, and the share of households with a toilet from 50.0% in Rewa to 83.3% in Indore, Kozhikode and Patna. Copy the CSV lines into a text file called district_summary.csv.

Load the CSV and join it

  1. Open the Data Source Manager (Ctrl + L) and choose the Delimited Text tab. Browse to district_summary.csv, choose CSV as the format, and under geometry choose No geometry (attribute only table). Add it. It appears in the Layers panel as a table.
  2. Open the boundary layer's properties: double-click the layer, or right-click it and choose Properties…. Go to the Joins tab and click the Add new join button.
  3. Set Join layer to district_summary, Join field to district and Target field to DISTRICT.
  4. Under Joined fields, tick only the columns you need, and set a short Custom field name prefix such as s_ so the new columns are easy to find. Click OK, then OK again.
  5. Open the attribute table. The ten districts now carry values; the other 631 rows hold NULL in the joined columns. That is correct here, because the survey covers ten districts.

The QGIS manual describes this join as one-to-one, based on an attribute that both layers share, so the values must match exactly, letter for letter.

The name-mismatch problem

District names in survey and MIS files rarely match a boundary file exactly. The cell below joins a hand-typed MIS table to the ten names as they appear in the DataMeet file.

Only 5 of 10 districts match. Betul, Gaya, Kozhikode, Patna and Purnia get no value, because the MIS typed Baitul, Gaya with a trailing space, Calicut, PATNA and Purnea. QGIS would give no warning: those districts would simply be blank on the map, which reads as "no data" or, with some colour ramps, as "lowest".

After trimming spaces, fixing case and a three-line lookup, all 10 match. The second part shows the other trap: Aurangabad is a district in both Bihar and Maharashtra (the DataMeet 2011 file has both, along with other repeated names such as Bilaspur, Hamirpur and Pratapgarh), so joining on the name alone turns one row into two. Join on district and state, or better, on a code.

Join on a code when you can. A census or LGD district code does not change with spelling or script. If your survey carries the 2011 census code, join it to censuscode and the spelling problem disappears. If it carries only names, clean them first (see the OpenRefine course) and keep the lookup table with your project, so the next round's join uses the same fixes.
Exercise. In the fix cell, delete "Calicut": "Kozhikode" from the lookup and run. The count drops to 9 of 10, and the printed table shows which district lost its value.
Module 5 of 8

Choropleth styling and classification

  1. Open the boundary layer's properties and go to Symbology.
  2. Change the renderer at the top from Single Symbol to Graduated.
  3. Set Value to the joined field, for example s_mean_pc_exp.
  4. Pick a Color ramp: one hue from light to dark for a quantity where more is more.
  5. On the Classes tab, set the number of classes and the Mode, then click Classify. The Histogram tab shows where the class breaks fall on the distribution of values.

The classification modes

The QGIS manual lists these modes for a graduated renderer:

Same data, different modes, different maps. The cell below puts the ten district means into four classes three ways. The breaks come from code written for this course (numpy quantiles, and an exact search for natural breaks); QGIS computes its own, which may differ slightly, so compare them with the Histogram tab.

The three methods disagree. Equal interval (breaks at about Rs 3,486, 4,576 and 5,667) puts six districts in the lowest class, three in the second, none in the third and only Kozhikode in the top, because Kozhikode's Rs 6,757.5 stretches the range. Quantile puts Indore, Wayanad and Kozhikode together in the top class, although Kozhikode's mean is Rs 2,800 above Wayanad's, and it separates Udaipur (class 3) from Indore (class 4), which are Rs 147 apart. Natural breaks (about Rs 2,569, 2,962 and 3,957) keeps Udaipur, Indore and Wayanad together and leaves Kozhikode alone at the top. Three honest-looking maps of the same ten numbers would tell three different stories about Indore.

The chart draws each district as a dot on one line and the class breaks as dashed lines. In the equal-interval panel two of the three breaks fall in the empty stretch between Wayanad and Kozhikode; in the quantile panel the breaks crowd into the cluster of low values; the natural-breaks panel ends each class at the last district before a wide gap, so its lines sit on Patna, Betul and Wayanad.

Why the choice matters

Exercise. In the classes cell, change k = 4 to k = 3 and run. Does any method move Indore out of a class of its own?
Module 6 of 8

Honest legends

A legend is part of the claim the map makes. In the Classes list of the Graduated renderer, double-click a label to edit it; the QGIS manual notes you can also set the legend format and its precision. An empty class, like the third equal-interval class in the last module, still shows in the legend: delete it or change the breaks.

Module 7 of 8

Publishing a map of India

Maps of India that show the national or state boundaries carry an extra requirement. The Department of Science and Technology's Guidelines for acquiring and producing Geospatial Data and Geospatial Data Services including Maps (F.No.SM/25/02/2020 (Part-I), dated 15 February 2021) say in paragraph xiii:

"For political Maps of India of any scale including national, state and other boundaries, SoI published maps or SoI digital boundary data are the standard to be used, which shall be made easily downloadable for free and their digital display and printing shall be permissible. Others may publish such maps that adhere to these standards."

SoI is the Survey of India. Its website lists a Political Map of India, an Outline Map of India and state maps among its products. The same guidelines' paragraph xv says violations "will be dealt with under the applicable laws".

What that means for your map

Module 8 of 8

Export a print layout

A print layout is a page on which you arrange the map, legend, scale bar, title and notes, and from which you export a PDF or an image. The steps follow the QGIS 3.44 manual's print layout overview and output pages.

  1. Style the map in the main window first. Then choose Project ► New Print Layout… and give the layout a name.
  2. Click Add map on the toolbar and drag a rectangle on the page. The current map view is drawn inside it.
  3. Click Add legend and drag a rectangle. In the legend's item properties, remove layers that should not appear (the CSV table, for instance) and rename entries.
  4. Click Add scale bar and click on the page. Add a north arrow from the same toolbar if your audience expects one.
  5. Add labels for the title, the source line (survey, year, sample size) and the boundary attribution, for example DataMeet's suggested line with its licence.
  6. Export with Layout ► Export as PDF… or Layout ► Export as Image…. The manual notes that a PDF export puts every page of the layout into one file, and that image export writes one file per page.
  7. Save the project (Ctrl + S): the layout is saved inside it.
Before you send it. Read the exported PDF at the size it will be printed. Check that every class has a readable label with units, that no-data districts say so, that the source and licence lines are there, and, for a map of India, that the outline is the official one.

Where next

→

OpenRefine: cleaning messy survey and MIS data

Clean district and village names so the join matches.

→

Open Data Editor

Check the district table before you share it.

→

pandas for development data

Build weighted district summaries in code.

→

Data Visualization 101

Choosing charts and colours that tell the truth.

→

Survey Design 101

Sampling frames, districts and what an estimate can support.