Bubble Charts. Plotly Express vs. Plotly.graph_objects | by Darío Weitz | Towards Data Science

Data visualization to tell a story is the most primitive form of human communication. There are cave drawings dating back to 44,000 BC, long before written communication dating back to about 3,000 BC.
According to the theory of evolution, we are a visual species: we evolved in such a way that an enormous amount of mental resources are used for visual perception and knowledge acquisition. We pay much more attention to visuals elements than to words.
Our brain is a parallel image processor with a very wide bandwidth. Some data confirming the above: 90% of the information transmitted to our brain is visual; visual information is transmitted to the brain 60,000 times faster than the same information in text form; 65% of the student population is composed of visual learners.
Data visualization is a tool for communication. It is the most powerful way to tell the story present in our data and to communicate it to an appropriate audience. But in a universe full of screens and visual elements, we have to prevent our audience from reaching the symptom of visual fatigue.
So our charts and figures should: be visually interesting; show a clear story; have information to draw from; have an informative title, clearly labeled axes, appropriate legends, and preferably be a two-dimensional chart with no unnecessary elements.
When the nature of the message is to show a connection or correlation between three or more numerical variables, a good chart should help us find patterns, establish the presence or absence of correlations, identify outliers, and show the existence of clusters and gaps. Bubble charts are well-suited for such purposes.
Bubble charts are used to determine if at least three numerical variables are related or share some kind of pattern. A bubble or disk is drawn for each observation of a pair of numerical variables (A, B) positioning, in a Cartesian coordinate system, the disk horizontally according to the value of variable A and vertically according to variable B. A third numerical variable(C) is represented by means of the area of the bubble. You can even incorporate a fourth variable (D: numerical or categorical) using different colors in different bubbles.
The storytelling −to show relationships between three or four variables but not their exact values− is narrated from the shape that these data points generate as well as from the differences in the relative sizes of the bubbles or discs.
Under special circumstances, they could be used to show trends over time or to compare categorical variables. They are considered a natural extension of the scatter plot where the dots are replaced with bubbles or disks.
Plotly Express (PE) is a high-level wrapper for Plotly.py fully compatible with the rest of the Plotly ecosystem, simple, powerful, and somewhat similar to Seaborn. It’s free and can be used in commercial applications and products. The library includes functions to plot trendlines and maps, as well as to perform faceting and animations. With PE you can make interactive graphics online but you can also save them offline.
We worked with a dataset downloaded from Kaggle [1]. It belongs to nutrition data on 80 cereal products. The data were collected by students from Cornell University at a local Wegmans supermarket in the early 1990s [2]. We would like to know if there is any correlation between Consumer Reports ratings and some specific nutrition data (sugar, sodium, vitamins).
First, we imported Plotly Express as px, the Pandas library as pd and converted our csv file into a dataframe:
import pandas as pdimport plotly.express as pxdf = pd.read_csv(path + 'cereals.csv', index_col = False,                 header = 0,   sep = ';', engine='python')
The screenshot below shows the first ten records of the dataset:
A practical Data Exploration indicates that we only have to eliminate some rows with N/A values using df.dropna(inplace = True) and the dataset is ready for drawing a figure.
For the bubble chart in this article, the Plotly Express function is px.scatter and the corresponding parameters are: data_frame; x= a name of a column in data_frame representing one of the numerical variables; y= a name of a column in data_frame representing another numerical variable; size= a name of a column in data_frame representing the third numerical variable by means of the area of the bubbles.
df.dropna(inplace = True)fig0 = px.scatter(df, x = 'sugars', y = 'rating',size = 'vitamins')fig0.write_image(path + "figbubble0.png")fig0.show()
Undoubtedly, it is not an appropriate chart for useful storytelling.
We considered the bubble at 0 sugar and 93 rating to be an outlier. Instead of deleting the point, we established the y-axe in the range [0–80]. Also, we incorporated a fourth numerical variable using the color parameter in px.scatter.
We updated the chart with update.layout: set the title, the size of the font, the template, and the figure dimensions with width and height. Then we updated the x-axis and the y-axis (text, font, tickfont). We saved the chart as a static png file and, finally, we drew the chart.
fig1 = px.scatter(df, x = 'sugars', y = 'rating',                  size = 'vitamins',   color = 'sodium')fig1.update_layout(                   title = "Cereals Consumer Reports Ratings ",                   "title_font_size = 40,                       template = 'seaborn',                   width = 1600, height = 1400)fig1.update_xaxes(                  title_text = 'Sugar',                  title_font=dict(size=30, family='Verdana',                                    color='purple'),                  tickfont=dict(family='Calibri', color='black',                                 size=25))fig1.update_yaxes(                  title_text = "Rating", range = (0,80),                  title_font=dict(size=30, family='Verdana',                                   color='orange'),                  tickfont=dict(family='Calibri', color='black',                                 size=25)fig1.write_image(path + "figbubble1.png")fig1.show()
Figure 1 clearly shows a negative correlation between consumer ratings and the level of sugar in the cereals. The colored vertical scale at the right side indicates the amount of sodium (color = ‘sodium’). Since there is an even distribution of colored bubbles across the chart, we can conclude that the amount of sodium does not significantly influence consumer appreciation. Finally, the size of the bubbles is related to the number of vitamins present in the cereals. The figure shows a null relationship between ratings and vitamins.
The plotly.graph_objects module contains a hierarchy of Python classes. Figure is a primary class. Figure has a data attribute and a layout attribute. The data attribute has more than 40 objects, each one refers to a specific type of chart (trace) with its corresponding parameters. The layout attribute specifies the properties of the figure as a whole (axes, title, shapes, legends, etc.).
The conceptual idea with plotly.graph_objects is to use .add_trace(go.Scatter()) to create the figure and then add methods such as .update_layout(), .update_xaxes, .update_yaxes to manipulate the figure. Finally, we export the figure with .write_image() and render it with .show().
Note that we typed mode = ‘markers’ and a dict with color, colorspace, opacity, size, and other size parameters. Particularly, the sizeref attribute allows scaling the size of the bubbles while colorscale allows displaying a particular color palette. The text of the legend is indicated by means of the name attribute.
import plotly.graph_objects as gofig2 = go.Figure()sizeref = 2.*max(df['sodium'])/(150**2)fig2.add_trace(go.Scatter(                          x = df['sugars'], y = df['rating'],                          mode = 'markers',                          name = 'Size = vitamins * Color = sodium',                          marker = dict(color = df['sodium'],                          colorscale = 'portland',                          opacity = 0.8,size = df['vitamins'],                          sizemode = 'area', sizeref= sizeref,                          sizemin= 4, showscale = True                          )))fig2.update_layout(title = "Cereals Consumer Reports Ratings ",                   title_font_size = 40, template = 'seaborn',                   width = 1600, height = 1400)fig2.update_layout(legend=dict(                               yanchor="top", y=0.99,                               xanchor="left",x=0.01),                               legend_font_size= 20,                               showlegend = True)fig2.update_xaxes(title_text = 'Sugar',                  title_font=dict(size=30, family='Verdana',                                   color='purple'),                  tickfont=dict(family='Calibri', color='black',                                  size=25))fig2.update_yaxes(title_text = "Rating", range = (0,80),                  title_font=dict(size=30, family='Verdana',                                   color='orange'),                  tickfont=dict(family='Calibri', color='black',                                 size=25))fig2.write_image(path + "figbubble2.png")fig2.show()
To sum up:
Bubble charts are appropriate when we want to show relationships between three or four variables but not their exact values. Plotly Express and Plotly.graph_objects allow you to create high quality static images with few and consistent lines of code.
But you must be aware of the following warnings:
Keep in mind that the area of a bubble is not proportional to its radius, but to the square of it;
Unlike scatter plots, bubble charts do not improve with the increase in the number of data points;
They should not be used for the representation of zero or negative values since there are no negative or zero areas;
To show trends over time with bubble charts you always have to put the time variable on the horizontal axis.
If you find this article of interest, please read my previous (https://medium.com/@dar.wtz):
Area Charts with Plotly Express, Traces & Layout
towardsdatascience.com
Histograms with Plotly Express, Themes & Templates