▶️ Run the code cell below to import packages used in today's exercise.
import pandas as pd
import numpy as np
import plotly
import plotly.express as px
import plotly.graph_objects as go
import base64
import unittest
# plotly.io is a low-level interface for interacting with figures/
# plotly.io.templates lists available plotly templates
# https://plotly.com/python-api-reference/plotly.io.html
import plotly.io as pio
pd.set_option('display.max_columns', 50)
tc = unittest.TestCase()
# use plotly version 5.x.x
tc.assertEqual(plotly.__version__[:2], '5.', 'Plotly version mismatch')
tc.assertIsNotNone(go.Figure, 'Check whether you have correctly imported plotly.graph_objects with an alias go.')
tc.assertIsNotNone(px.scatter, 'Check whether you have correctly imported plotly.express with an alias px.')
▶️ Run the code below to import Chicago Airbnb listings dataset.
df_listings = pd.read_csv('https://github.com/bdi475/datasets/raw/main/case-studies/airbnb-sql/Chicago.csv')
df_listings_backup = df_listings.copy()
df_listings.head(3)
name | neighbourhood | room_type | bedrooms | bathrooms | accommodates | minimum_nights | price | availability_365 | number_of_reviews | review_score | latitude | longitude | is_superhost | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Hyde Park - Walk to UChicago, 10 min to McCormick | Hyde Park | Private room | 1.0 | 1.0 | 1 | 2 | 65.0 | 355 | 181 | 100.0 | 41.78790 | -87.58780 | 1 |
1 | 394 Great Reviews. 127 y/o House. 40 yds to tr... | South Lawndale | Entire home/apt | 3.0 | 1.0 | 7 | 2 | 117.0 | 184 | 395 | 96.0 | 41.85495 | -87.69696 | 1 |
2 | Tiny Studio Apartment 94 Walk Score | West Town | Entire home/apt | 3.0 | 1.0 | 2 | 2 | 70.0 | 365 | 389 | 93.0 | 41.90289 | -87.68182 | 1 |
# YOUR CODE BEGINS
num_rows = df_listings.shape[0]
num_cols = df_listings.shape[1]
# YOUR CODE ENDS
print(f'There are {num_rows} rows and {num_cols} columns in the dataset.')
There are 3217 rows and 14 columns in the dataset.
# DO NOT CHANGE THE CODE IN THIS CELL
tc.assertEqual(num_rows, len(df_listings_backup.index), f'Number of rows should be {len(df_listings_backup.index)}')
tc.assertEqual(num_cols, len(df_listings_backup.columns), f'Number of columns should be {len(df_listings_backup.columns)}')
# YOUR CODE BEGINS
df_under_200_sample = df_listings[df_listings["price"] < 200].sample(100)
# YOUR CODE ENDS
display(df_under_200_sample.head(3))
name | neighbourhood | room_type | bedrooms | bathrooms | accommodates | minimum_nights | price | availability_365 | number_of_reviews | review_score | latitude | longitude | is_superhost | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1533 | Edgewater, private, charming coach house 2 ( o... | Edgewater | Entire home/apt | 1.0 | 1.0 | 3 | 2 | 89.0 | 301 | 40 | 99.0 | 41.98715 | -87.66177 | 1 |
2532 | GOATHOTE | SPACIOUS/VINTAGE STYLE 2/1APT | CHI... | West Town | Entire home/apt | 2.0 | 1.0 | 10 | 1 | 58.0 | 356 | 55 | 84.0 | 41.89488 | -87.68642 | 0 |
3043 | Private Condo Apartment on Belmont Cragin Area | Belmont Cragin | Entire home/apt | 3.0 | 2.0 | 8 | 2 | 92.0 | 72 | 12 | 100.0 | 41.93793 | -87.78125 | 1 |
# DO NOT CHANGE THE CODE IN THIS CELL
tc.assertEqual(df_under_200_sample.shape, (100, df_listings_backup.shape[1]), 'Incorrect number of rows and/or columns')
tc.assertFalse((df_under_200_sample['price'] >= 200).any(), 'Listing priced equal to or greater than 200 found')
df_under_200_sample
, create a scatter plot with the following axes:x
: Number of bedroomsy
: Number of bathroomsplotly_dark
theme.width
to 800
and height
to 400
.fig
.fig.show()
# YOUR CODE BEGINS
fig = px.scatter(
df_under_200_sample,
title='Bedrooms & Bathrooms Scatter Plot',
x="bedrooms",
y="bathrooms",
size="price",
color="room_type",
template='plotly_dark',
width=800,
height=400
)
fig.show()
# YOUR CODE ENDS
# DO NOT CHANGE THE CODE IN THIS CELL
tc.assertEqual(len(fig.data), df_under_200_sample['room_type'].nunique(), f'Did you specify a column to differentiate colors?')
tc.assertIsNotNone(fig.layout.title.text, 'Missing figure title')
num_points = 0
for i in range(len(fig.data)):
tc.assertEqual(fig.data[i].type, 'scatter', 'Must be a scatter3d plot')
num_points += fig.data[i].x.shape[0]
tc.assertEqual(num_points, 100, 'There must be 100 points')
tc.assertEqual(fig.layout.width, 800, 'Incorrect width')
tc.assertEqual(fig.layout.height, 400, 'Incorrect height')
tc.assertEqual(fig.layout.template, pio.templates['plotly_dark'], 'Incorrect plotly theme (template)')
This exercise is highly similar to the previous one. Instead of using size to differentiate price of each point, we'll use add a new axis. This makes it a 3D scatter plot! 🤡
df_under_200_sample
, create a 3D scatter plot with the following axes:x
: Number of bedroomsy
: Number of bathroomsz
: Priceplotly_dark
theme.width
to 800
and height
to 600
.fig
.fig.show()
# YOUR CODE BEGINS
fig = px.scatter_3d(
df_under_200_sample,
title='Bedrooms, Bathrooms, Price 3D Scatter Plot',
x="bedrooms",
y="bathrooms",
z="price",
color="room_type",
template='plotly_dark',
width=800,
height=600
)
fig.show()
# YOUR CODE ENDS
# DO NOT CHANGE THE CODE IN THIS CELL
tc.assertEqual(len(fig.data), df_under_200_sample['room_type'].nunique(), f'Did you specify a column to differentiate colors?')
tc.assertIsNotNone(fig.layout.title.text, 'Missing figure title')
num_points = 0
for i in range(len(fig.data)):
tc.assertEqual(fig.data[i].type, 'scatter3d', 'Must be a scatter3d plot')
num_points += fig.data[i].x.shape[0]
tc.assertEqual(num_points, 100, 'There must be 100 points')
tc.assertEqual(fig.layout.width, 800, 'Incorrect width')
tc.assertEqual(fig.layout.height, 600, 'Incorrect height')
tc.assertEqual(fig.layout.template, pio.templates['plotly_dark'], 'Incorrect plotly theme (template)')
df_listings
(by number of listings).top_20_neighbourhoods
.top_20_neighbourhoods
should be a Python list
type.# YOUR CODE BEGINS
top_20_neighbourhoods = df_listings['neighbourhood'].value_counts().head(20).index.tolist()
# YOUR CODE ENDS
top_20_neighbourhoods
['West Town', 'Lake View', 'Logan Square', 'Near North Side', 'Lincoln Park', 'Near West Side', 'Lower West Side', 'Edgewater', 'Uptown', 'North Center', 'Irving Park', 'Loop', 'Avondale', 'Rogers Park', 'Near South Side', 'Bridgeport', 'Lincoln Square', 'Grand Boulevard', 'Hyde Park', 'Armour Square']
# DO NOT CHANGE THE CODE IN THIS CELL
decoded_code = base64.b64decode(b'dG9wXzIwX25laWdoYm91cmhvb2RzX2NoZWNrID0gZGZfbGlzd\
GluZ3NbJ25laWdoYm91cmhvb2QnXS52YWx1ZV9jb3VudHMoKS5oZWFkKDIwKS5pbmRleC50b2xpc3QoKQ==')
eval(compile(decoded_code, '<string>', 'exec'))
tc.assertEqual(set(top_20_neighbourhoods), set(top_20_neighbourhoods_check), 'Incorrect neighbourhoods')
df_listings
, filter only the rows where the neighbourhood
is in top_20_neighbourhoods
and the price is less than 300.df_filtered
.# YOUR CODE BEGINS
df_filtered = df_listings[(df_listings['neighbourhood'].isin(top_20_neighbourhoods)) \
& (df_listings['price'] < 300)]
# YOUR CODE ENDS
display(df_filtered.head(3))
print(df_filtered.shape)
name | neighbourhood | room_type | bedrooms | bathrooms | accommodates | minimum_nights | price | availability_365 | number_of_reviews | review_score | latitude | longitude | is_superhost | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Hyde Park - Walk to UChicago, 10 min to McCormick | Hyde Park | Private room | 1.0 | 1.0 | 1 | 2 | 65.0 | 355 | 181 | 100.0 | 41.78790 | -87.58780 | 1 |
2 | Tiny Studio Apartment 94 Walk Score | West Town | Entire home/apt | 3.0 | 1.0 | 2 | 2 | 70.0 | 365 | 389 | 93.0 | 41.90289 | -87.68182 | 1 |
3 | Barbara's Hideaway - Old Town | Lincoln Park | Entire home/apt | 1.0 | 1.0 | 4 | 4 | 95.0 | 282 | 54 | 93.0 | 41.91769 | -87.63788 | 1 |
(2391, 14)
# DO NOT CHANGE THE CODE IN THIS CELL
decoded_code = base64.b64decode(b'dG9wXzIwX25laWdoYm91cmhvb2RzX2NoZWNrID0g\
ZGZfbGlzdGluZ3NfYmFja3VwWyduZWlnaGJvdXJob29kJ10udmFsdWVfY291bnRzKCkuaGVhZC\
gyMCkuaW5kZXgudG9saXN0KCkKCmRmX2ZpbHRlcmVkX2NoZWNrID0gZGZfbGlzdGluZ3NfYmFj\
a3VwWyhkZl9saXN0aW5nc19iYWNrdXBbJ25laWdoYm91cmhvb2QnXS5pc2luKHRvcF8yMF9uZW\
lnaGJvdXJob29kc19jaGVjaykpICYgKGRmX2xpc3RpbmdzX2JhY2t1cFsncHJpY2UnXSA8IDMwMCld')
eval(compile(decoded_code, '<string>', 'exec'))
tc.assertEqual(df_filtered.shape, df_filtered_check.shape, 'Incorrect number of rows and/or columns')
pd.testing.assert_frame_equal(
df_filtered.sort_values(df_filtered.columns.tolist()).reset_index(drop=True),
df_filtered_check.sort_values(df_filtered_check.columns.tolist()).reset_index(drop=True)
)
df_filtered
, create a pie chart that shows the breakdown of neighbourhoods (by number of listings).width
to 800
and height
to 700
.fig
.fig.show()
# YOUR CODE BEGINS
fig = px.pie(
df_filtered,
names='neighbourhood',
title='Neighbourhood breakdown',
width=800,
height=700
)
fig.show()
# YOUR CODE ENDS
# DO NOT CHANGE THE CODE IN THIS CELL
tc.assertIsNotNone(fig.layout.title.text, 'Missing figure title')
tc.assertEqual(fig.data[0].type, 'pie', 'Must be a pie chart')
tc.assertEqual(set(fig.data[0].labels), set(top_20_neighbourhoods), 'Must only use the top 20 neighbourhoods')
tc.assertEqual(fig.layout.width, 800, 'Incorrect width')
tc.assertEqual(fig.layout.height, 700, 'Incorrect height')
df_filtered
, create a heatmap to visualize the distribution of listings price by neighbourhood.neighbourhood
on the x-axis and price
on the y-axis.height
to 600
(do not specify width
).fig
.fig.show()
# YOUR CODE BEGINS
fig = px.density_heatmap(
df_filtered,
x='neighbourhood',
y='price',
title='Neighbourhood vs Price Heatmap',
height=600
)
fig.show()
# YOUR CODE ENDS
# DO NOT CHANGE THE CODE IN THIS CELL
decoded_code = base64.b64decode(b'ZmlnX2NoZWNrID0gcHguZGVuc2l0eV9oZWF0bWFwKAogICAgZGZfZ\
mlsdGVyZWQsCiAgICB4PSduZWlnaGJvdXJob29kJywKICAgIHk9J3ByaWNlJywKICAgIGhlaWdodD02MDAKKQ==')
eval(compile(decoded_code, '<string>', 'exec'))
tc.assertIsNotNone(fig.layout.title.text, 'Missing figure title')
tc.assertEqual(fig.data[0].type, 'histogram2d', 'Must be a heatmap (histogram2d)')
tc.assertEqual(set(fig.data[0].x), set(fig_check.data[0].x), 'Incorrect x-axis value(s)')
tc.assertEqual(set(fig.data[0].y), set(fig_check.data[0].y), 'Incorrect y-axis value(s)')
tc.assertEqual(fig.layout.height, fig_check.layout.height, 'Incorrect height')
df_filtered
, calculate the following aggregated values by neighbourhood
and room_type
.num_listings
: Number of listingsbedrooms
: Average number of bedroomsbathrooms
: Average number of bathroomsprice
: Average pricedf_by_neighbourhood_room_type
.df_by_neighbourhood_room_type = df_filtered.groupby(['neighbourhood', 'room_type'], as_index=False) \
.agg({
'name': 'count',
'bedrooms': 'mean',
'bathrooms': 'mean',
'accommodates': 'mean',
'price': 'mean'
}).rename(columns={
'name': 'num_listings'
})
# YOUR CODE BEGINS
df_by_neighbourhood_room_type = df_filtered.groupby(['neighbourhood', 'room_type'], as_index=False) \
.agg({
'name': 'count',
'bedrooms': 'mean',
'bathrooms': 'mean',
'accommodates': 'mean',
'price': 'mean'
}).rename(columns={
'name': 'num_listings'
})
# YOUR CODE ENDS
display(df_by_neighbourhood_room_type.head(5))
neighbourhood | room_type | num_listings | bedrooms | bathrooms | accommodates | price | |
---|---|---|---|---|---|---|---|
0 | Armour Square | Entire home/apt | 22 | 3.090909 | 1.545455 | 9.000000 | 167.454545 |
1 | Armour Square | Private room | 25 | 1.000000 | 1.760000 | 1.920000 | 44.480000 |
2 | Avondale | Entire home/apt | 59 | 1.932203 | 1.152542 | 4.932203 | 92.084746 |
3 | Avondale | Private room | 9 | 1.111111 | 1.055556 | 1.666667 | 70.888889 |
4 | Avondale | Shared room | 1 | 1.000000 | 1.000000 | 1.000000 | 30.000000 |
# DO NOT CHANGE THE CODE IN THIS CELL
decoded_code = base64.b64decode(b'dG9wXzIwX25laWdoYm91cmhvb2RzX2NoZWNrID0gZGZfbGlzdGluZ3Nf\
YmFja3VwWyduZWlnaGJvdXJob29kJ10udmFsdWVfY291bnRzKCkuaGVhZCgyMCkuaW5kZXgudG9saXN0KCkKCmRmX2\
ZpbHRlcmVkX2NoZWNrID0gZGZfbGlzdGluZ3NfYmFja3VwWyhkZl9saXN0aW5nc19iYWNrdXBbJ25laWdoYm91cmhv\
b2QnXS5pc2luKHRvcF8yMF9uZWlnaGJvdXJob29kc19jaGVjaykpICYgKGRmX2xpc3RpbmdzX2JhY2t1cFsncHJpY2\
UnXSA8IDMwMCldCgpkZl9ieV9uZWlnaGJvdXJob29kX3Jvb21fdHlwZV9jaGVjayA9IGRmX2ZpbHRlcmVkLmdyb3Vw\
YnkoWyduZWlnaGJvdXJob29kJywgJ3Jvb21fdHlwZSddLCBhc19pbmRleD1GYWxzZSkgXAogICAgLmFnZyh7CiAgIC\
AgICAgJ25hbWUnOiAnY291bnQnLAogICAgICAgICdiZWRyb29tcyc6ICdtZWFuJywKICAgICAgICAnYmF0aHJvb21z\
JzogJ21lYW4nLAogICAgICAgICdhY2NvbW1vZGF0ZXMnOiAnbWVhbicsCiAgICAgICAgJ3ByaWNlJzogJ21lYW4nCi\
AgICB9KS5yZW5hbWUoY29sdW1ucz17CiAgICAgICAgJ25hbWUnOiAnbnVtX2xpc3RpbmdzJwogICAgfSk=')
eval(compile(decoded_code, '<string>', 'exec'))
tc.assertEqual(
df_by_neighbourhood_room_type.shape,
df_by_neighbourhood_room_type_check.shape,
'Incorrect number of rows and/or columns'
)
pd.testing.assert_frame_equal(
df_by_neighbourhood_room_type.sort_values(df_by_neighbourhood_room_type.columns.tolist()).reset_index(drop=True),
df_by_neighbourhood_room_type_check.sort_values(df_by_neighbourhood_room_type_check.columns.tolist()).reset_index(drop=True)
)
df_by_neighbourhood_room_type
, create a bar chart describing the number of listings by neighbourhood (broken down into room types).num_listings
on the x-axis and neighbourhood
on the y-axis.fig.update_yaxes(...)
.height
to 600
(do not specify width
).plotly_dark
theme.fig
.fig.show()
# YOUR CODE BEGINS
fig = px.bar(
df_by_neighbourhood_room_type,
x='num_listings',
y='neighbourhood',
color='room_type',
template='plotly_dark',
title='Listings Breakdown by Neighbourhood and Room Type',
height=600
)
fig.update_yaxes(categoryorder='total ascending')
fig.show()
# YOUR CODE ENDS
tc.assertIsNotNone(fig.layout.title.text, 'Missing figure title')
tc.assertEqual(fig.layout.height, 600, 'Incorrect height')
decoded_code = base64.b64decode(b'CmZpZ19jaGVjayA9IHB4LmJhcigKICAgIGRmX2J5X25laWdoYm91\
cmhvb2Rfcm9vbV90eXBlLAogICAgeD0nbnVtX2xpc3RpbmdzJywKICAgIHk9J25laWdoYm91cmhvb2QnLAogIC\
AgY29sb3I9J3Jvb21fdHlwZScsCiAgICB0ZW1wbGF0ZT0ncGxvdGx5X2RhcmsnLAogICAgdGl0bGU9J0xpc3Rp\
bmdzIEJyZWFrZG93biBieSBOZWlnaGJvdXJob29kIGFuZCBSb29tIFR5cGUnLAogICAgaGVpZ2h0PTYwMAopCg\
pmaWdfY2hlY2sudXBkYXRlX3lheGVzKGNhdGVnb3J5b3JkZXI9J3RvdGFsIGFzY2VuZGluZycpCg=='
)
eval(compile(decoded_code, '<string>', 'exec'))
for fig_index in range(len(fig.data)):
fig_data = fig.data[fig_index]
fig_check_data = fig_check.data[fig_index]
tc.assertEqual(fig_data.type, fig_check_data.type, f'Must be a {fig_check_data.type} chart')
np.testing.assert_array_equal(
fig_data.x,
fig_check_data.x,
'x value(s) mismatch'
)
np.testing.assert_array_equal(
fig_data.y,
fig_check_data.y,
'y value(s) mismatch'
)
np.testing.assert_array_equal(
fig_data.name,
fig_check_data.name,
'Name(s) mismatch'
)
tc.assertEqual(fig.layout.template, pio.templates['plotly_dark'], 'Incorrect plotly theme (template)')
df_by_neighbourhood_room_type
, create a sunburst chart describing the breakdown of the listings by neighbourhood and room type.800
.fig
.fig.show()
# YOUR CODE BEGINS
fig = px.sunburst(
df_by_neighbourhood_room_type,
path=['neighbourhood', 'room_type'],
title='Listings Breakdown by Neighbourhood and Room Type',
values='num_listings',
width=800,
height=800
)
fig.show()
# YOUR CODE ENDS
tc.assertIsNotNone(fig.layout.title.text, 'Missing figure title')
tc.assertEqual(fig.data[0].type, 'sunburst', 'Must be a sunburst chart')
tc.assertEqual(fig.layout.width, 800, 'Incorrect width')
tc.assertEqual(fig.layout.height, 800, 'Incorrect height')
decoded_code = base64.b64decode(b'CmZpZ19jaGVjayA9IHB4LnN1bmJ1cnN0KAogICAg\
ZGZfYnlfbmVpZ2hib3VyaG9vZF9yb29tX3R5cGUsCiAgICBwYXRoPVsnbmVpZ2hib3VyaG9vZC\
csICdyb29tX3R5cGUnXSwKICAgIHRpdGxlPSdMaXN0aW5ncyBCcmVha2Rvd24gYnkgTmVpZ2hi\
b3VyaG9vZCBhbmQgUm9vbSBUeXBlJywKICAgIHZhbHVlcz0nbnVtX2xpc3RpbmdzJywKICAgIH\
dpZHRoPTgwMCwKICAgIGhlaWdodD05MDAKKQo='
)
eval(compile(decoded_code, '<string>', 'exec'))
np.testing.assert_array_equal(
fig.data[0].labels,
fig_check.data[0].labels,
'Label(s) mismatch'
)
np.testing.assert_array_equal(
fig.data[0].parents,
fig_check.data[0].parents,
'Parent(s) mismatch'
)
np.testing.assert_array_equal(
fig.data[0].values,
fig_check.data[0].values,
'Value(s) mismatch'
)
▶️ Run the code below to create a treemap chart describing the distribution of listings by neighbourhood.
df_by_neighbourhood_room_type
, create a treemap chart that shows the breakdown of neighbourhoods by number of listings.height
to 700
.fig
.fig.show()
# YOUR CODE BEGINS
fig = px.treemap(
df_by_neighbourhood_room_type,
path=['neighbourhood'],
title='Top 20 neighbourhoods breakdown',
values='num_listings',
height=700
)
fig.show()
# YOUR CODE ENDS
tc.assertIsNotNone(fig.layout.title.text, 'Missing figure title')
decoded_code = base64.b64decode(b'CmZpZ19jaGVjayA9IHB4LnRyZWVtYXAoCiAgICBkZl9\
ieV9uZWlnaGJvdXJob29kX3Jvb21fdHlwZSwKICAgIHBhdGg9WyduZWlnaGJvdXJob29kJ10sCiAg\
ICB0aXRsZT0nVG9wIDIwIG5laWdoYm91cmhvb2RzIGJyZWFrZG93bicsCiAgICB2YWx1ZXM9J251b\
V9saXN0aW5ncycsCiAgICBoZWlnaHQ9NzAwCikK'
)
eval(compile(decoded_code, '<string>', 'exec'))
tc.assertEqual(fig.data[0].type, 'treemap', 'Must be a treemap')
np.testing.assert_array_equal(
fig.data[0].ids,
fig_check.data[0].ids,
'ID value(s) mismatch'
)
np.testing.assert_array_equal(
fig.data[0].labels,
fig_check.data[0].labels,
'Label value(s) mismatch'
)
np.testing.assert_array_equal(
fig.data[0].parents,
fig_check.data[0].parents,
'Parent value(s) mismatch'
)
np.testing.assert_array_equal(
fig.data[0].values,
fig_check.data[0].values,
'Size value(s) mismatch'
)
df_by_neighbourhood_room_type
, create a treemap chart that shows the breakdown of neighbourhoods by number of listings and then by room types.height
to 700
.fig
.fig.show()
# YOUR CODE BEGINS
fig = px.treemap(
df_by_neighbourhood_room_type,
path=['neighbourhood', 'room_type'],
title='Top 20 neighbourhoods breakdown',
values='num_listings',
height=700
)
fig.show()
# YOUR CODE ENDS
tc.assertIsNotNone(fig.layout.title.text, 'Missing figure title')
decoded_code = base64.b64decode(b'CmZpZ19jaGVjayA9IHB4LnRyZWVtYXAoCiAgICBkZl9ie\
V9uZWlnaGJvdXJob29kX3Jvb21fdHlwZSwKICAgIHBhdGg9WyduZWlnaGJvdXJob29kJywgJ3Jvb21f\
dHlwZSddLAogICAgdGl0bGU9J1RvcCAyMCBuZWlnaGJvdXJob29kcyBicmVha2Rvd24nLAogICAgdmF\
sdWVzPSdudW1fbGlzdGluZ3MnLAogICAgaGVpZ2h0PTcwMAopCg==')
eval(compile(decoded_code, '<string>', 'exec'))
tc.assertEqual(fig.data[0].type, 'treemap', 'Must be a treemap')
np.testing.assert_array_equal(
fig.data[0].ids,
fig_check.data[0].ids,
'ID value(s) mismatch'
)
np.testing.assert_array_equal(
fig.data[0].labels,
fig_check.data[0].labels,
'Label value(s) mismatch'
)
np.testing.assert_array_equal(
fig.data[0].parents,
fig_check.data[0].parents,
'Parent value(s) mismatch'
)
np.testing.assert_array_equal(
fig.data[0].values,
fig_check.data[0].values,
'Size value(s) mismatch'
)