MACH-IV questionnaire

Behind the screens: Likert scale visualization

Hans Weda
Orikami blog
Published in
10 min readNov 12, 2019

--

How to visualize results from Likert scale questionnaires in Python.

Likert scales are used in many different fields to assess opinions. This article discusses how to best plot Likert scale results using diverging stacked bar graphs in Python by means of a practical example.

What are Likert scales?

A couple of years ago, I worked on a project analyzing patient opinions about newly refurbished emergency waiting rooms in a hospital in Århus, Denmark. The assumption was that patients would like the new waiting rooms better, feel safer, and perceive shorter waiting times. To assess patients’ opinions, we asked them their level of agreement ranging from ‘fully agree’ to ‘fully disagree’ on several statements about the rooms.

This type of rating scale, which asks the respondent to choose from an ordered, discrete set of options, is a Likert scale. Likert scales are used in many fields of research and marketing, for example to investigate personality differences between groups in psychology or check consumer opinions on website functionality in marketing surveys.

A Likert scale is made of several questions or statements. The respondent answers by choosing from a set of answer options (see Figure 1). These options are a discrete set. The options cover a range of possible answers, and are ordered, like ‘fully disagree’, ‘disagree’, ‘no opinion’, ‘agree’, and ‘fully agree’. Other ranges also work, for example from ‘very dissatisfied’ to ‘very satisfied’. Using five response options is common, but some use scales with up to seven or nine options. Sometimes the neutral or ‘no opinion’ option is omitted to force the respondent to make a choice. The pro’s and con’s of adding the neutral option are subject of discussion.

Scales with a continuous range also exist and are called Visual Analogue Scale (VAS). These are not Likert scales, and we’ll discuss them another time.

Figure 1: An example questionnaire using the Likert scale. The respondent indicates their level of agreement on each statement.

How to visualize Likert scale results?

Back in Århus, with the patient responses in hand, I had to decide how to best present the results to the client. That meant creating a visualization that the client could look at to understand the data.

Visually impressive images miss the mark when the person looking at them cannot quickly and accurately understand their meaning.

Survey results are often presented in tables, or several forms of bar- or pie-charts. Choosing the right visualization is essential. As a data scientist, the priority must go to accurate understanding over pretty images. As William S. Cleveland points out in his well-known book Elements of Graphing Data: Visually impressive images miss the mark when the person looking at them cannot quickly and accurately understand their meaning.

In designing visualizations, data scientists should remember that humans are notoriously bad at comparing angles and areas. However, they do fairly well in comparing line lengths or bar heights. Presenting results in the wrong type of graph can lead to misinterpretation and incorrect conclusions.

Diverging stacked bar graphs

When analyzing Likert scale results it is often useful to compare all positive and negative responses. Both Heiberger and Robbins argue that such comparisons are best done with diverging stacked bar graphs. Also called centred count graphs or aggregated stacked bars, they are essentially bar charts laid on their sides with results centred around the zero line. All positive responses run to the right from zero and all negative responses run left from zero (see Figure 2). This design makes it easy to compare the total number of positive or negative responses.

Figure 2: A diverging stacked bar graph. The figure comes from the HH package which Heiberger and Robbins made available in R.

Implementation in R

Heiberger and Robbins created the HH-package to make their plotting functions available in R. R is the leading scripting language among statisticians and is also frequently used by academics. The plotting functions in this package are very flexible and allow many different plot options, such as adding extra comparison categories, and plotting results either side-by-side or below each other. Depending on what you want to focus on, you can show total counts, percentages, or eliminate the neutral option.

The demonstration code in the package quickly plots default examples, one of which is shown in Figure 2. This figure show the results of a survey that compares the influence of respondent background on professional recognition. In this figure, answers are centred on the neutral option ‘no opinion’. The reader can quickly visually compare the positive and negative answers. The demonstration code also provides many other examples.

Like all good visualization methods, this one uses an inclusive design that takes different user needs into account.

The package uses carefully selected colours selected from the HCL (hue-chroma-luminance) color space. The HCL color space uses a perceptual model in which steps of equal size are represented by equally different colors. Therefore this color space is more appropriate to chose your color pallet from than, say, the RGB (red-green-blue) color space. Base colours red and blue work best for people with the most prevalent color vision deficiencies. Like all good visualization methods, this one uses an inclusive design that takes different user needs into account. This solution stand out from all others with it’s high level of sophistication and unparalleled eye for detail.

Do it yourself!

Running the demonstration code on a toy-dataset from the HH package is cute, but it becomes really useful when you apply the package to your own data. Let’s try to build a graph using the HH package in R. I’m using the MACH-IV questionnaire from Christie and Geis, which provides a measure of Machiavellianism. Named after the diplomat, philosopher and poet Niccolò Machiavelli, Machiavellianism is the political theory on how to use all means to maintain political power. Machiavellianism is also used in modern psychology to describe a lack of empathy and morality, and a strong focus on personal gain.

The MACH-IV questionnaire consists of twenty statements taken from Machiavelli’s work and respondents rate their agreement on a five point scale from ‘strongly disagree’ to ‘strongly agree’. It has been used in various studies, including one that examined the study of ethical propensities of accounting students. The questionnaire is widely available and you can even take it yourself. The raw data of another previous experiment can be downloaded from the Open Psychology Data. The top 10 rows of raw data are shown in Table 1 below.

Table 1: Raw data from the MACH-IV questionnaire, showing the first 10 rows only.

The downloaded raw data is stored in the so-called ‘long’ data format: the response of each respondent is listed on a separate row. The questions are labelled Q1 to Q20 and the table also stores a total score, gender, age, and the time needed to complete the questionnaire. The first step in working with this data is to convert it into a format that is more convenient to use.

For example, the raw data lists gender as ‘1’ or ‘2’, which can be confusing to work with. We use the codebook published with the dataset to translate integers into the strings ‘male’ and ‘female’, which are easier for humans to understand.

After refactoring some more numeric variables, I have massaged the data table into a more suitable form by removing odd values, aggregating over respondents, and pivoting part of the table. I have also added an age category to the data by splitting the respondents in four groups of approximately equal size. This process results in the table below.

Table 2: Refactored and reformatted MACH-IV data

With the hard work of refactoring the table and creating the right format done, plotting is easy. If we want to compare the responses of different age groups, this can be done as follows in R:

likert(category ~ . | question, 
subset(quest, subtable=='age'),
main='Machiavellianism',
ylab='Age categories',
as.percent=T,
layout=c(1,5))

Executing this code results in the plot below. I am showing five of the twenty available questions for brevity.

Figure 3: The responses on five items for the different age categories. The total row counts are plotted on the right hand axis.

Other comparisons are easily made by changing a few options in the code. The code below results in a plot that compares the responses between males and females:

likert(question ~ . | category, 
subset(quest, subtable=='gender'),
main='Machiavellianism',
ylab=NULL,
as.percent=T,
rightAxis=F,
positive.order = T)
Figure 4: Comparing the responses on five items between males and females.

Implementation in Python

Implementation in R is impressive and allows for very versatile plotting options. However, Python is the upcoming hipster scripting language. It’s used more in commercial environments and often used by data scientists. However, Python does not create divergent stacked bar graphs easily. So how can we create these graphs in Python?

Implementation in Python using rpy2

A logical option would be to use the rpy2 Python library, a set of codes that allows the coder to call R functions from Python. It is important to both understand R and Python, before using the library because error messages can be quite incomprehensible. Spaces in the column names are translated to ‘.’ in R and need to be changed back. Setting these small inconveniences apart, we can get a nice plot by inserting the following code into a Jupyter notebook, a web application that allows users to create documents that contain executable code together with narrative text and figures.

%%R -i quest -w 10 -h 5 -u in -r 400
# replacing '.' in colnames by spaces which were lost in the
# transition from Python to R
colnames(quest) <- gsub('\\.', ' ', colnames(quest))likert(question ~ ., data=quest,
main="Machiavellianism",
ylab=NULL,
scales=list(y=list(relation="free")), layout=c(1,1),
positive.order=T)
Figure 5: Comparing the total answers on five MACH-IV questions. The plot is generated in Jupyter notebook with the help of the rpy2 Python library.

Making this solution work in the virtual environments where data scientists often execute projects is challenging. A virtual environment has its own set of variables, and specific versions of packages or libraries. They allow the data scientist to use different versions of packages or libraries in each project. Loading the packages and setting all the environment variables for good collaboration between R and Python is quite a hassle. Solutions that use only one language are preferred, so let’s look at a full Python solutions.

Custom implementation in Python

The custom implementation in Python takes the stacked bar graph from Matplotlib as starting point. This graph does not diverge from the middle, so we’ll use a trick. Using this post from stackoverflow, I first insert an ‘invisible’ column to the left, so that all columns are nicely lined up around the middle. The code is shown below:

The code to automatically calculate the proper tick labels and positions is lengthy and replaced by manual assignment for brevity. Additionally, placing the legend neatly is also complex. Note that the colors need to be manually set to avoid Pythons colourful default set, which doesn’t make sense in this case. This code results in the plot below.

Figure 6. Comparing the total answers on five MACH-IV questions. The plot is generated in Jupyter notebook using the default stacked bar graph from Matplotlib, a frequently used plotting library in Python.

This code shows how to plot the ‘easy’ case: a comparison of the total answers. Splitting up the plot to compare answers between male and female, or to analyse differences between age categories can be done, but requires many extra lines of code to create proper text boxes and alignment of the figures.

Implementation in Python using Altair

Another interesting approach is to use the trendy Altair Python library. This library is an alternative to Matplotlib and approaches plotting in a more object oriented way. Object oriented programming is a specific programming paradigm. The code below is based on the Altair documentation.

This method requires explicit calculation of the start and end of each column, but doesn’t need an invisible column. The resulting figure is shown below. The ticks on the x-axis are neatly produced by Altair, and do not need extra tweaking. The labels on the y-axis are automatically chopped to specific length, which may be convenient if the reader knows all the questions, but does not give us a self-contained plot.

Figure 7. Comparing the total answers on five MACH-IV questions. The plot is generated in Jupyter notebook using Altair.

Summarizing

Visualization is an important part of data science.

Visualization is an important part of data science. Proper presentation of Likert scale results is critical in good communication to stakeholders. The best plot to use for visualizing Likert scales is a diverging stacked bar chart and the go-to method is definitely the HH-package in R. When R is not available, or not preferred, there is no optimal solution in Python yet. At Orikami, we built our own toolbox to offer our clients quality divergent stacked bar graph visualizations while still using Python.

Closing words

When analysing the attitudes of Århus’ patients towards the newly decorated emergency rooms, I was lucky enough to come across diverging stacked bar graphs and applied the HH-package in R to the problem at hand. The client was happy with the visualization and decided to use the results in a product leaflet.

For future projects, we are no longer bound to R and can use our toolbox to efficiently help clients obtain high quality graphs in Python. It is part of Orikami’s DNA to perform thorough analyses and create effective visualization of the results that can be read and understood by the user. As a result, the user can make informed healthcare or business decisions.

The work of visualization creation and improving is on-going, for me and for you. I’m interested in alternative methods for visualization Likert scale results as well as any other visualization tips or stories you’d care to share. Please share your comments and suggestions below!

--

--