I'm trying to replicate this chart but I am having a hard time placing all 3 charts I created into one graph. I've so far been able to create 3 individual bar charts with the appropriate data and color but was not successful with layering.
This is the code I am using to create each chart. It's essentially the same code repeated 3 separate times to create each individual chart with the name of each chart labeled 'seen_movies_top', 'seen_movies_middle', and 'seen_movies_bottom'. I feel like I'm overdoing it here and that there is an easier way to go about this but I'm happy to have been able to at least create each individual chart. Now just to get them on the same graph..
# fix the labels a bit so will create a mapping to the full names
episodes = ['EI', 'EII', 'EIII', 'EIV', 'EV', 'EVI']
names = {
'EI' : 'The Phantom Meanance', 'EII' : 'Attack of the clones', 'EIII' : 'Revenge of the Sith',
'EIV': 'A New Hope', 'EV': 'The Empire Strikes Back', 'EVI' : 'The Return of the Jedi'
}
# going to use this order to sort, so names_l will now have our sort order
names_l = [names[ep] for ep in episodes]
print("sort order: ",names_l)
seen_every = seen_at_least_one.dropna(subset=['seen_EI','seen_EII','seen_EIII','seen_EIV','seen_EV','seen_EVI'])
# only use those people who have seen at least one movie, let's get the people, toss NAs
# and get the total count
# find people who have at least on of the columns (seen_*) not NaN
seen_at_least_one = sw.dropna(subset=['seen_' + ep for ep in episodes],how='all')
total = len(seen_every)
seen_every = seen_at_least_one.dropna(subset=['seen_EI','seen_EII','seen_EIII','seen_EIV','seen_EV','seen_EVI'])
print("total who have seen at least one: ", total)
total_rank = len(seen_every)
# calculating the percents and generating a new data frame
percs_seen_top3 = []
# looping over each column and calculating the number of people who have seen the movie
# specifically, filter out the people who are *NaN* for a specific episode (e.g., ep_EII), count them
# and divide by the percent
for rank_ep in ['rank_' + ep for ep in episodes]:
#my_value_count = seen_every[rank_ep].value_counts()
perc_seen_top3 = (seen_every[rank_ep].value_counts()['1'] + seen_every[rank_ep].value_counts()['2'])/ total_rank
percs_seen_top3.append(perc_seen_top3)
# creating tuples--pairing names with percents--using "zip" and then making a dataframe
tuples_top = list(zip([names[ep] for ep in episodes],percs_seen_top3))
seen_per_df_top = pd.DataFrame(tuples_top, columns = ['Name', 'Percentage'])
bars_top = alt.Chart(seen_per_df_top).mark_bar(size=20).encode(
# encode x as the percent, and hide the axis
x=alt.X(
'Percentage',
axis=None),
y=alt.Y(
# encode y using the name, use the movie name to label the axis, sort using the names_l
'Name:N',
axis=alt.Axis(tickCount=5, title=''),
# we give the sorting order to avoid alphabetical order
sort=names_l
)
)
text_top = bars_top.mark_text(
align='left',
baseline='middle',
dx=3 # Nudges text to right so it doesn't appear on top of the bar
).encode(
# we'll use the percentage as the text
text=alt.Text('Percentage:Q',format='.0%')
)
seen_movies_top = (text_top + bars_top).configure_mark(
color='#008fd5'
).configure_view(
# we don't want a stroke around the bars
strokeWidth=0
).configure_scale(
# add some padding
bandPaddingInner=0.2
).properties(
# set the dimensions of the visualization
width=500,
height=180
).properties(
# add a title
title={
"text":["How People Rate the 'Star Wars' Movies"],
"subtitle":["How often each film was rated in the top, middle and bottom third (by 471 respondents who have seen all six films)"]}
).configure_title(
# customize title and sub-title
fontSize=30, align='left',anchor ='start', fontWeight='bold', subtitleFontWeight='lighter'
)
seen_movies_top
percs_seen_middle3 = []
for rank_ep in ['rank_' + ep for ep in episodes]:
#my_value_count = seen_every[rank_ep].value_counts()
perc_seen_middle3 = (seen_every[rank_ep].value_counts()['3'] + seen_every[rank_ep].value_counts()['4'])/ total_rank
percs_seen_middle3.append(perc_seen_middle3)
tuples_middle = list(zip([names[ep] for ep in episodes],percs_seen_middle3))
seen_per_df_middle = pd.DataFrame(tuples_middle, columns = ['Name', 'Percentage'])
# ok, time to make the chart... let's make a bar chart (use mark_bar)
bars_middle = alt.Chart(seen_per_df_middle).mark_bar(size=20).encode(
# encode x as the percent, and hide the axis
x=alt.X(
'Percentage',
axis=None),
y=alt.Y(
# encode y using the name, use the movie name to label the axis, sort using the names_l
'Name:N',
axis=alt.Axis(tickCount=5, title=''),
# we give the sorting order to avoid alphabetical order
sort=names_l
)
)
# at this point we don't really have a great plot (it's missing the annotations, titles, etc.)
bars_middle
text_middle = bars_middle.mark_text(
align='left',
baseline='middle',
dx=3 # Nudges text to right so it doesn't appear on top of the bar
).encode(
# we'll use the percentage as the text
text=alt.Text('Percentage:Q',format='.0%')
)
seen_movies_middle = (text_middle + bars_middle).configure_mark(
# we don't love the blue
color='#69a14f'
).configure_view(
# we don't want a stroke around the bars
strokeWidth=0
).configure_scale(
# add some padding
bandPaddingInner=0.2
).properties(
# set the dimensions of the visualization
width=500,
height=180
).properties(
# add a title
title={
"text":["How People Rate the 'Star Wars' Movies"],
"subtitle":["How often each film was rated in the top, middle and bottom third (by 471 respondents who have seen all six films)"]}
).configure_title(
# customize title and sub-title
fontSize=30, align='left',anchor ='start', fontWeight='bold', subtitleFontWeight='lighter'
)
seen_movies_middle
percs_seen_bottom3 = []
for rank_ep in ['rank_' + ep for ep in episodes]:
#my_value_count = seen_every[rank_ep].value_counts()
perc_seen_bottom3 = (seen_every[rank_ep].value_counts()['5'] + seen_every[rank_ep].value_counts()['6'])/ total_rank
percs_seen_bottom3.append(perc_seen_bottom3)
tuples_bottom = list(zip([names[ep] for ep in episodes],percs_seen_bottom3))
seen_per_df_bottom = pd.DataFrame(tuples_bottom, columns = ['Name', 'Percentage'])
# ok, time to make the chart... let's make a bar chart (use mark_bar)
bars_bottom = alt.Chart(seen_per_df_bottom).mark_bar(size=20).encode(
# encode x as the percent, and hide the axis
x=alt.X(
'Percentage',
axis=None),
y=alt.Y(
# encode y using the name, use the movie name to label the axis, sort using the names_l
'Name:N',
axis=alt.Axis(tickCount=5, title=''),
# we give the sorting order to avoid alphabetical order
sort=names_l
)
)
# at this point we don't really have a great plot (it's missing the annotations, titles, etc.)
bars_bottom
text_bottom = bars_bottom.mark_text(
align='left',
baseline='middle',
dx=3 # Nudges text to right so it doesn't appear on top of the bar
).encode(
# we'll use the percentage as the text
text=alt.Text('Percentage:Q',format='.0%')
)
seen_movies_bottom = (text_bottom + bars_bottom).configure_mark(
# we don't love the blue
color='#fd3a4a'
).configure_view(
# we don't want a stroke around the bars
strokeWidth=0
).configure_scale(
# add some padding
bandPaddingInner=0.2
).properties(
# set the dimensions of the visualization
width=500,
height=180
).properties(
# add a title
title={
"text":["How People Rate the 'Star Wars' Movies"],
"subtitle":["How often each film was rated in the top, middle and bottom third (by 471 respondents who have seen all six films)"]}
).configure_title(
# customize title and sub-title
fontSize=30, align='left',anchor ='start', fontWeight='bold', subtitleFontWeight='lighter'
)
seen_movies_bottom




