├── .ipynb_checkpoints └── How to Use-checkpoint.ipynb ├── How to Use.ipynb ├── PlotLikertOverConditions.py ├── README.md ├── __pycache__ └── PlotLikertOverConditions.cpython-36.pyc ├── after_condition_questions.csv ├── example.png ├── general_questions.csv └── requirements.txt /.ipynb_checkpoints/How to Use-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import pandas as pd\n", 10 | "from PlotLikertOverConditions import *" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "# Python code for plotting stacked bar charts for Likert Scales " 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "! Dependencies: numpy, matplotlib, pandas, and seaborn" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "## Example 1: Only ploting after condition questions" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [ 38 | "The csv file should have a format similar to 'eg1.csv' where condition indices are writen in one column and other columns include the likert scale responces for different questions that participnats are asked to answer after each condition. Number of rows should be equal to number_of_participants*number_of_conditions\n" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": null, 44 | "metadata": {}, 45 | "outputs": [], 46 | "source": [ 47 | "df1=data=pd.read_csv('after_condition_questions.csv')\n", 48 | "df1.head(3)" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "\n", 58 | "PlotLikertOverConditions(df1,5)" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "## Example 2: Only ploting after condition questions + custom labels for Likert min/max" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "## Customize Likert min/max labels\n", 75 | "customLikertRange={1:['very easy','very difficult'] ,\n", 76 | " 2:['very intuitive','very unnatural'] ,\n", 77 | " 3:['very low','very high'] ,\n", 78 | " 4:['very low','very high'] }\n", 79 | "PlotLikertOverConditions(df1,5 ,customLikertRange)\n" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": {}, 85 | "source": [ 86 | "## Example 3: Adding a few general questions (questions been asked at the end) to the same plot" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "Have all general questions in a seperate table. Number of rows should be equal to the number of participants" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": null, 99 | "metadata": { 100 | "scrolled": true 101 | }, 102 | "outputs": [], 103 | "source": [ 104 | "df2=data=pd.read_csv('general_questions.csv')\n", 105 | "df2.head()\n", 106 | "\n", 107 | "## Likert min/max labels for the general questions\n", 108 | "customLikertRange2={1:['no effort','a lot of effort'] }\n", 109 | "PlotLikertOverConditions(df1,5,customLikertRange,df2,customLikertRange2)" 110 | ] 111 | } 112 | ], 113 | "metadata": { 114 | "kernelspec": { 115 | "display_name": "Python 3", 116 | "language": "python", 117 | "name": "python3" 118 | }, 119 | "language_info": { 120 | "codemirror_mode": { 121 | "name": "ipython", 122 | "version": 3 123 | }, 124 | "file_extension": ".py", 125 | "mimetype": "text/x-python", 126 | "name": "python", 127 | "nbconvert_exporter": "python", 128 | "pygments_lexer": "ipython3", 129 | "version": "3.6.5" 130 | }, 131 | "toc": { 132 | "nav_menu": {}, 133 | "number_sections": true, 134 | "sideBar": true, 135 | "skip_h1_title": false, 136 | "title_cell": "Table of Contents", 137 | "title_sidebar": "Contents", 138 | "toc_cell": false, 139 | "toc_position": {}, 140 | "toc_section_display": true, 141 | "toc_window_display": false 142 | } 143 | }, 144 | "nbformat": 4, 145 | "nbformat_minor": 2 146 | } 147 | -------------------------------------------------------------------------------- /How to Use.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import pandas as pd\n", 10 | "from PlotLikertOverConditions import *" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "# Python code for plotting stacked bar charts for Likert Scales " 18 | ] 19 | }, 20 | { 21 | "cell_type": "markdown", 22 | "metadata": {}, 23 | "source": [ 24 | "! Dependencies: numpy, matplotlib, pandas, and seaborn" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "## Example 1: Only ploting after condition questions" 32 | ] 33 | }, 34 | { 35 | "cell_type": "markdown", 36 | "metadata": {}, 37 | "source": [ 38 | "The csv file should have a format similar to 'eg1.csv' where condition indices are writen in one column and other columns include the likert scale responces for different questions that participnats are asked to answer after each condition. Number of rows should be equal to number_of_participants*number_of_conditions\n" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": null, 44 | "metadata": {}, 45 | "outputs": [], 46 | "source": [ 47 | "df1=data=pd.read_csv('after_condition_questions.csv')\n", 48 | "df1.head(3)" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "\n", 58 | "PlotLikertOverConditions(df1,5)" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "## Example 2: Only ploting after condition questions + custom labels for Likert min/max" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": null, 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "## Customize Likert min/max labels\n", 75 | "customLikertRange={1:['very easy','very difficult'] ,\n", 76 | " 2:['very intuitive','very unnatural'] ,\n", 77 | " 3:['very low','very high'] ,\n", 78 | " 4:['very low','very high'] }\n", 79 | "PlotLikertOverConditions(df1,5 ,customLikertRange)\n" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": {}, 85 | "source": [ 86 | "## Example 3: Adding a few general questions (questions been asked at the end) to the same plot" 87 | ] 88 | }, 89 | { 90 | "cell_type": "markdown", 91 | "metadata": {}, 92 | "source": [ 93 | "Have all general questions in a seperate table. Number of rows should be equal to the number of participants" 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": null, 99 | "metadata": { 100 | "scrolled": true 101 | }, 102 | "outputs": [], 103 | "source": [ 104 | "df2=data=pd.read_csv('general_questions.csv')\n", 105 | "df2.head()\n", 106 | "\n", 107 | "## Likert min/max labels for the general questions\n", 108 | "customLikertRange2={1:['no effort','a lot of effort'] }\n", 109 | "PlotLikertOverConditions(df1,5,customLikertRange,df2,customLikertRange2)" 110 | ] 111 | } 112 | ], 113 | "metadata": { 114 | "kernelspec": { 115 | "display_name": "Python 3", 116 | "language": "python", 117 | "name": "python3" 118 | }, 119 | "language_info": { 120 | "codemirror_mode": { 121 | "name": "ipython", 122 | "version": 3 123 | }, 124 | "file_extension": ".py", 125 | "mimetype": "text/x-python", 126 | "name": "python", 127 | "nbconvert_exporter": "python", 128 | "pygments_lexer": "ipython3", 129 | "version": "3.6.5" 130 | }, 131 | "toc": { 132 | "nav_menu": {}, 133 | "number_sections": true, 134 | "sideBar": true, 135 | "skip_h1_title": false, 136 | "title_cell": "Table of Contents", 137 | "title_sidebar": "Contents", 138 | "toc_cell": false, 139 | "toc_position": {}, 140 | "toc_section_display": true, 141 | "toc_window_display": false 142 | } 143 | }, 144 | "nbformat": 4, 145 | "nbformat_minor": 2 146 | } 147 | -------------------------------------------------------------------------------- /PlotLikertOverConditions.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on March 20, 2017 3 | 4 | @author: Diako Mardanbegi 5 | ''' 6 | 7 | import seaborn as sns 8 | import matplotlib.patches as patches 9 | import pandas as pd 10 | import numpy as np 11 | import matplotlib.pyplot as plt 12 | import math as math 13 | from pylab import * 14 | import io, os, sys, types 15 | pd.options.mode.chained_assignment = None # default='warn' 16 | sns.set_style("whitegrid") 17 | mpl.rc("savefig", dpi=150) 18 | 19 | def PlotLikertOverConditions(tb,nPoint,customLikertRange=None,tb2=None,customLikertRange2=None): 20 | # This functions gets a table of questions and their responces in likert scale (1:positive N:negative) as coulmns, as well as a another column indicating the condition of the responce 21 | # This function can also get another table for general questions after all conditions 22 | 23 | 24 | Qs=tb.columns.tolist() 25 | CustomLikertLabels_orderd_by_y_axis=[] 26 | 27 | df=tb.copy(deep=True) 28 | likert_colors= sns.color_palette("coolwarm", nPoint) 29 | likert_colors=[(1.0,1.0,1.0)]+likert_colors 30 | 31 | 32 | font1 = {'family': 'sans-serif','color': 'white','weight': 'normal','size': 10,} 33 | font2 = {'family': 'sans-serif','color': 'grey','weight': 'normal','size': 8,} 34 | LikertRange=[1,2,3,4,5] 35 | fig, ax = plt.subplots(1, 1,figsize=(10,8)) 36 | 37 | 38 | ##-------------------------------------------------------------------- 39 | ##Seperate into conditions and count the scores for each 40 | df_conds=[] 41 | middles_all=[] 42 | # df.loc[:,'condition']=df['condition'].astype(np.int32) 43 | 44 | barwidth=0.2 45 | def SHIFT(N,i): 46 | return float(i)*barwidth*1.0-(float(N)-1)*barwidth 47 | 48 | 49 | conds=[] 50 | for cond in df['condition'].unique(): 51 | conds.append(cond) 52 | temp=df[df['condition']==cond] 53 | temp.drop('condition', axis=1,inplace=True) 54 | temp=pd.DataFrame(temp.stack()) 55 | temp=pd.DataFrame(temp.unstack(0)) 56 | 57 | 58 | g= lambda x,y: x.loc[y] if y in x.index else 0 59 | temp2=temp.copy(deep=True) 60 | for q in range(1,len(Qs)): 61 | for i in range(1,nPoint+1): 62 | # print 'there was %s of %s in Q %s'%(g(temp.loc[Qs[q],:].value_counts(),i),i,q) 63 | temp2.loc[Qs[q], i]=g(temp.loc[Qs[q],:].value_counts(),i) 64 | 65 | temp2.drop(0, axis=1,inplace=True) 66 | temp2.columns = temp2.columns.droplevel(level=1) 67 | # print temp2 68 | df_conds.append( temp2) 69 | middles_all.append(temp2[LikertRange[:len(LikertRange)//2]].sum(axis=1)+temp2[len(LikertRange)//2+1]*.5) 70 | 71 | 72 | ##-------------------------------------------------------------------- 73 | ## general questions 74 | df_conds_generals=[] 75 | middles_all_generals=[] 76 | ## here we add general questions as well if there is any! 77 | if type(tb2)==pd.core.frame.DataFrame: 78 | temp=tb2.copy(deep=True) 79 | temp2=tb2.T.copy(deep=True) 80 | 81 | for gQ, g_col in temp.iteritems(): 82 | g= lambda x,y: x.loc[y] if y in x.index else 0 83 | for i in range(1,nPoint+1): 84 | temp2.loc[gQ, i]=g(g_col.astype(np.int32,inplace=True).value_counts(),i) 85 | 86 | temp2=temp2.loc[:,range(1,nPoint+1)] 87 | # print temp2 88 | df_conds_generals= temp2 89 | middles_all_generals=temp2[LikertRange[:len(LikertRange)//2]].sum(axis=1)+temp2[len(LikertRange)//2+1]*.5 90 | 91 | 92 | ##-------------------------------------------------------------------- 93 | 94 | ## add shift column to each table 95 | if len(np.array(middles_all_generals))==0: 96 | longest= max(map(max, np.array(middles_all)) ) 97 | else: 98 | longest= max(max(map(max, np.array(middles_all)) ),max(np.array(middles_all_generals)) ) 99 | 100 | 101 | 102 | patches_already_moved=[] 103 | for cond,df_c in enumerate(df_conds): 104 | 105 | df_c.insert(0, '', (middles_all[cond] - longest).abs()) 106 | complete_longest=int(longest+(df_c[:].sum(axis=1).max()-longest))#in our case is 16 107 | 108 | patch_handles = [] 109 | 110 | patch_handles.append(df_c.plot.barh(ax=ax,stacked=True, color=likert_colors, legend=False, 111 | width=barwidth,edgecolor='white'))#,alpha=1.0-(float(cond)/len(df_conds))*0.7 112 | 113 | shift=SHIFT(len(df_conds),cond) 114 | 115 | for j in range(len(patch_handles)): 116 | for i, p in enumerate(patch_handles[j].get_children()): 117 | 118 | 119 | if type(p)==(matplotlib.patches.Rectangle): 120 | 121 | if p.get_height()==barwidth and not (p in patches_already_moved): 122 | # print (p in patches_already_moved), 123 | 124 | p.set_xy((p.get_x(),p.get_y()+shift)) 125 | 126 | 127 | if p.get_width()>1 and p.get_facecolor()[0:3]!=likert_colors[0]:#p.get_facecolor()!=(1.0, 1.0, 1.0, 1.0): 128 | # if cond % 2 == 0: 129 | # p.set_hatch('\ '*cond) 130 | # else: 131 | # p.set_hatch('/ '*cond) 132 | 133 | patch_handles[j].text( 134 | p.get_x()+p.get_width()/2., 135 | p.get_y()+ p.get_height() /(len(Qs)-1), 136 | "{0:.0f}%".format(p.get_width()/(len(tb)/len(tb['condition'].unique())) * 100), 137 | ha="center", 138 | fontdict=font1)#.set_zorder(-1) 139 | 140 | 141 | 142 | patches_already_moved=patches_already_moved+patch_handles[j].get_children() 143 | 144 | yticks=list(ax.get_yticks()) 145 | # print customLikertRange 146 | CustomLikertLabels_orderd_by_y_axis=[customLikertRange[key] if (customLikertRange!=None and customLikertRange.get(key)) 147 | else ['very low','very high'] 148 | for key in (ax.get_yticks()+1)] 149 | 150 | 151 | if type(tb2)==pd.core.frame.DataFrame: 152 | CustomLikertLabels_orderd_by_y_axis=[customLikertRange2[key] if (customLikertRange2!=None and customLikertRange2.get(key)) 153 | else ['very low','very high'] 154 | for key in range(1,len(df_conds_generals)+1)][::-1]+CustomLikertLabels_orderd_by_y_axis 155 | 156 | 157 | ## Plotting general questions 158 | def SHIFT2(i): 159 | i=i+0.1 160 | extra=0.5 161 | return -1.3 -(i*(2*(barwidth)+extra)) 162 | 163 | df_conds_generals.insert(0, '', (middles_all_generals - longest).abs()) 164 | for i in range(0,len(df_conds_generals)): 165 | y=SHIFT2(i-0.1) 166 | yticks=[y]+ yticks 167 | y=y+barwidth/2.0 168 | ax.plot([-5,df_conds_generals.iloc[i,0]],[y,y],linestyle=':', color='grey', alpha=.2,linewidth=1) 169 | 170 | 171 | 172 | patch_handles = [] 173 | patch_handles.append(df_conds_generals.plot.barh(ax=ax,stacked=True, color=likert_colors, legend=False, 174 | width=barwidth,edgecolor='white')) 175 | 176 | for j in range(len(patch_handles)): 177 | for i, p in enumerate(patch_handles[j].get_children()): 178 | 179 | 180 | if type(p)==(matplotlib.patches.Rectangle): 181 | 182 | if p.get_height()==barwidth and not (p in patches_already_moved): 183 | shift=SHIFT2(p.get_y()) 184 | 185 | p.set_xy((p.get_x(),shift)) 186 | if p.get_width()>1 and p.get_facecolor()[0:3]!=likert_colors[0]:#p.get_facecolor()!=(1.0, 1.0, 1.0, 1.0): 187 | 188 | patch_handles[j].text( 189 | p.get_x()+p.get_width()/2., 190 | shift+ p.get_height() /(len(Qs)-1), 191 | "{0:.0f}%".format(p.get_width()/(len(tb)/len(tb['condition'].unique())) * 100), 192 | ha="center", 193 | fontdict=font1)#.set_zorder(-1) 194 | 195 | 196 | 197 | patches_already_moved=patches_already_moved+patch_handles[j].get_children() 198 | 199 | 200 | z = ax.axvline(longest, linestyle='-', color='black', alpha=.5,linewidth=1) 201 | z.set_zorder(-1) 202 | # print longest 203 | 204 | 205 | plt.xlim(-5, complete_longest+5) 206 | ymin=-1*len(df_conds_generals)-1 207 | plt.ylim(ymin,len(Qs)-1.5) 208 | 209 | xvalues = range(0, complete_longest,10) 210 | xlabels = []#[str(x-longest) for x in xvalues] 211 | plt.xticks(xvalues, xlabels) 212 | plt.xlabel('Percentage', fontsize=12,horizontalalignment='left') 213 | ax.xaxis.set_label_coords(float(longest)/(complete_longest+5),-0.01) 214 | 215 | general_Qs=[] if len(df_conds_generals)==0 else df_conds_generals.index.values.tolist() #+[''] 216 | ylabels =general_Qs +Qs[1:] 217 | 218 | plt.yticks(yticks, ylabels) 219 | 220 | for tick in ax.yaxis.get_major_ticks(): 221 | tick.label.set_fontsize(12) 222 | 223 | 224 | ## adding condition indicators on the y axis 225 | for cond,df_c in enumerate(df_conds): 226 | shift=SHIFT(len(df_conds),cond) 227 | for row in range(0,len(df_c)): 228 | 229 | y=row+shift 230 | x=ax.get_xlim()[0]+0.5 231 | # x=ax.get_xlim()[0]+1.3 232 | ax.text( 233 | x, 234 | y-barwidth/4.0, 235 | # str(cond), 236 | # 'C ' + str(cond+1), 237 | conds[cond], 238 | ha="center", 239 | fontdict=font2) 240 | ax.plot([x+0.7,df_c.iloc[row,0]],[y,y],linestyle=':', color='grey', alpha=.2,linewidth=1) 241 | 242 | 243 | 244 | plt.grid('off') 245 | ax.spines['left'].set_visible(False) 246 | ax.spines['top'].set_visible(False) 247 | ax.spines['right'].set_visible(False) 248 | # print yticks 249 | ## adding Likert range legend 250 | for i,y_tick in enumerate(yticks): 251 | 252 | v=CustomLikertLabels_orderd_by_y_axis[i] 253 | x=-12 254 | 255 | y=yticks[i]-0.4 256 | ax.text(x,y, v[0],fontsize = 8,zorder = 6, color = 'white',horizontalalignment='right', 257 | bbox={'edgecolor':'none','facecolor':likert_colors[1], 'alpha':1.0, 'pad':2}) 258 | 259 | middle_colors=likert_colors[1:-1] 260 | for ci,c in enumerate(middle_colors): 261 | x=x+0.3 262 | ax.text(x,y,' ',fontsize = 8,zorder = 6, color = 'white',horizontalalignment='right', 263 | bbox={'edgecolor':'none','facecolor':middle_colors[ci], 'alpha':1.0, 'pad':2}) 264 | 265 | 266 | ax.text(x+0.2,y,v[1],fontsize = 8,zorder = 6, color = 'white',horizontalalignment='left', 267 | bbox={'edgecolor':'none','facecolor':likert_colors[-1], 'alpha':1.0, 'pad':2}) 268 | plt.tight_layout() 269 | plt.savefig('example.png') 270 | plt.show() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python code for plotting stacked bar charts for Likert Scale questionnaire 2 | 3 | ## Installation 4 | ```brew 5 | pip install -r requirements.txt 6 | ``` 7 | 8 | ## Usage 9 | 10 | Find examples in the "How to Use.ipynb" file 11 | 12 | ![My image](https://github.com/dmardanbeigi/Likert_Scale_Plot_in_Python/blob/master/example.png) 13 | 14 | 15 | -------------------------------------------------------------------------------- /__pycache__/PlotLikertOverConditions.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DMardanbegi/Likert_Scale_Plot_in_Python/9ef51d7f3ce8940df38f12c57aaa61da51e7a876/__pycache__/PlotLikertOverConditions.cpython-36.pyc -------------------------------------------------------------------------------- /after_condition_questions.csv: -------------------------------------------------------------------------------- 1 | condition,I found it easy to complete the task.,I felt confident in using the technique.,How mentally demanding was the task?,How physically demanding was the task? 2 | cond1,1,2,1,2 3 | cond2,2,1,1,2 4 | cond4,1,1,1,2 5 | cond3,1,1,1,1 6 | cond2,1,1,1,1 7 | cond3,1,1,1,2 8 | cond1,2,1,1,1 9 | cond4,1,1,1,2 10 | cond3,1,1,1,1 11 | cond4,1,1,1,1 12 | cond2,1,1,1,1 13 | cond1,1,1,1,1 14 | cond4,2,1,1,1 15 | cond1,4,4,3,5 16 | cond3,2,1,1,1 17 | cond2,3,1,1,2 18 | cond1,2,3,1,2 19 | cond2,1,2,1,2 20 | cond4,2,2,1,3 21 | cond3,1,1,1,3 22 | cond2,3,3,1,1 23 | cond3,2,2,1,2 24 | cond1,2,2,2,1 25 | cond4,1,1,1,2 26 | cond3,1,1,4,5 27 | cond4,2,2,5,5 28 | cond2,3,3,5,5 29 | cond1,1,1,4,4 30 | cond4,1,1,1,2 31 | cond1,1,1,1,2 32 | cond3,1,1,1,2 33 | cond2,2,1,1,3 34 | cond1,1,2,2,1 35 | cond2,3,3,4,1 36 | cond4,1,1,4,1 37 | cond3,1,1,2,1 38 | cond4,1,1,1,1 39 | cond1,1,1,1,2 40 | cond3,1,1,1,1 41 | cond2,2,1,1,2 42 | cond1,1,1,1,2 43 | cond2,3,2,2,2 44 | cond4,1,1,1,2 45 | cond3,1,1,1,2 46 | cond2,2,2,2,1 47 | cond3,2,2,2,2 48 | cond1,3,3,2,3 49 | cond4,2,1,1,2 50 | cond3,1,1,1,3 51 | cond4,1,1,1,3 52 | cond2,1,1,1,1 53 | cond1,1,1,1,1 54 | cond4,2,2,2,2 55 | cond1,1,1,2,1 56 | cond3,1,1,2,2 57 | cond2,1,1,2,1 58 | cond3,1,1,3,4 59 | cond4,1,2,3,4 60 | cond2,2,2,4,5 61 | cond1,1,1,3,4 62 | cond2,2,4,1,1 63 | cond3,1,1,1,1 64 | cond1,1,1,1,1 65 | cond4,4,4,4,4 -------------------------------------------------------------------------------- /example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DMardanbegi/Likert_Scale_Plot_in_Python/9ef51d7f3ce8940df38f12c57aaa61da51e7a876/example.png -------------------------------------------------------------------------------- /general_questions.csv: -------------------------------------------------------------------------------- 1 | general question 1 2 | 4 3 | 1 4 | 2 5 | 4 6 | 2 7 | 4 8 | 4 9 | 3 10 | 5 11 | 1 12 | 3 13 | 1 14 | 2 15 | 1 16 | 5 17 | 2 -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | matplotlib==2.0.0 2 | numpy==1.11.1 3 | pandas==0.20.2 4 | seaborn==0.7.1 5 | --------------------------------------------------------------------------------