Create a 100 % stacked area chart with matplotlib - python

I was wondering how to create a 100 % stacked area chart in matplotlib. At the matplotlib page I couldn't find an example for it.
Somebody here can show me how to achieve that?

A simple way to achieve this is to make sure that for every x-value, the y-values sum to 100.
I assume that you have the y-values organized in an array as in the example below, i.e.
y = np.array([[17, 19, 5, 16, 22, 20, 9, 31, 39, 8],
[46, 18, 37, 27, 29, 6, 5, 23, 22, 5],
[15, 46, 33, 36, 11, 13, 39, 17, 49, 17]])
To make sure the column totals are 100, you have to divide the y array by its column sums, and then multiply by 100. This makes the y-values span from 0 to 100, making the "unit" of the y-axis percent. If you instead want the values of the y-axis to span the interval from 0 to 1, don't multiply by 100.
Even if you don't have the y-values organized in one array as above, the principle is the same; the corresponding elements in each array consisting of y-values (e.g. y1, y2 etc.) should sum to 100 (or 1).
The below code is a modified version of the example #LogicalKnight linked to in his comment.
import numpy as np
from matplotlib import pyplot as plt
fnx = lambda : np.random.randint(5, 50, 10)
y = np.row_stack((fnx(), fnx(), fnx()))
x = np.arange(10)
# Make new array consisting of fractions of column-totals,
# using .astype(float) to avoid integer division
percent = y / y.sum(axis=0).astype(float) * 100
fig = plt.figure()
ax = fig.add_subplot(111)
ax.stackplot(x, percent)
ax.set_title('100 % stacked area chart')
ax.set_ylabel('Percent (%)')
ax.margins(0, 0) # Set margins to avoid "whitespace"
plt.show()
This gives the output shown below.

Related

Python - display list of solid colors

I have a list of RGB values and I need to plot them as a set of squares, each representing a different solid color. Using plt.imshow I get an array with nine colors, instead of three as intended. How can I fix this? Thanks
import matplotlib.pyplot as plt
rgb_values = np.array([[ 47, 32, 31], [ 14, 10, 12], [119, 122, 141]])
plt.imshow(rgb_values)

Creating a heatmap with uneven block sizes / stacked bar chart using Python

I want to create a heatmap in Python that is similar to what is shown on the bottom of this screenshot from TomTom Move: https://d2altcye8lkl9f.cloudfront.net/2021/03/image-1.png (source: https://support.move.tomtom.com/ts-output-route-analysis/)
A route contains multiple segments that vary in length. Each segment consists of the average speed which I want to color using the colormap (green for fast speed to yellow to red for slow speed). I was able to plot each segment in their correct order using a stacked histplot, but when I add hue, it orders the segments with the fastest average speeds first to slowest, and not the segments in their correct order.
There are three time sets containing 4 segments with their length, length of the route so far and speed for each segment for each time set.
import pandas as pd
d = {'timeRanges': ['00:00-06:30', '00:00-06:30', '00:00-06:30', '00:00-06:30', '07:00-15:00', '07:00-15:00', '07:00-15:00', '07:00-15:00', '16:00-17:30', '16:00-17:30', '16:00-17:30', '16:00-17:30'], 'segmentOrder': [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3], 'segmentDistance': [20, 45, 60, 30, 20, 45, 60, 30, 20, 45, 60, 30], 'distanceAlongRoute': [20, 65, 125, 155, 20, 65, 125, 155, 20, 65, 125, 155], 'averageSpeed': [54.2, 48.1, 23.5, 33.7, 56.2, 53.2, 42.5, 44.2, 50.2, 46.2, 35.3, 33.2]}
df = pd.DataFrame(data=d)
I have tried using seaborn heatmap and imshow and I have yet to make the x axis block widths vary for each segment.
Much appreciated.
Here is a simple example of a heatmap with different box sizes. Based on the example "Heatmap with Unequal Block Sizes" https://plotly.com/python/heatmaps/. Just set the xe variable to all of the x-axis edges and z to the values that will be used for determining the colors between those points. There should be 1 fewer z value than xe value.
import plotly.graph_objects as go
import numpy as np
xe = [0, 1, 2, 5, 6]
ye = [0, 1]
z = [[1, 2, 1, 3]]
fig = go.Figure(data=go.Heatmap(
x = np.sort(xe),
y = np.sort(ye),
z = z,
type = 'heatmap',
colorscale = 'Viridis'))
fig.update_layout(margin = dict(t=200,r=200,b=200,l=200),
showlegend = False,
width = 700, height = 500,
autosize = False
)
fig.show()

How to update y-axis in matplotlib

I have problem update limits on y-axis.
My idea is to read some csv file, and to plot some graphs.
When I set limits for y-axis, it doesn't show on the plot.
It always shows, values from file.
I'm new in python.
import matplotlib.pyplot as plt
import csv
import numpy as np
x = []
y = []
chamber_temperature = []
with open(r"C:\Users\mm02058\Documents\test.txt", 'r') as file:
reader = csv.reader(file, delimiter = '\t')
for row in (reader):
x.append(row[0])
chamber_temperature.append(row[1])
y.append(row[10])
x.pop(0)
y.pop(0)
chamber_temperature.pop(0)
#print(chamber_temperature)
arr = np.array(chamber_temperature)
n_lines = len(arr)
time = np.arange(0,n_lines,1)
time_sec = time * 30
time_min = time_sec / 60
time_hour = time_min / 60
time_day = time_hour / 24
Fig_1 = plt.figure(figsize=(10,8), dpi=100)
plt.suptitle("Powered Thermal Cycle", fontsize=14, x=0.56, y= 0.91)
plt.subplot(311, xlim=(0, 30), ylim=(-45,90), xticks=(0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30), yticks=( -40, -30, -20, -10, 0, 10, 20, 30, 40, 50, 60, 70, 80, 90), ylabel=("Temperature [°C]"))
plt.plot(time_hour, chamber_temperature, 'k', label='Temperature')
plt.gca().invert_yaxis()
plt.grid()
plt.legend(shadow=True, fontsize=('small'), loc = 'center right', bbox_to_anchor=(1.13, 0.5))
plt.show()
Your code looks suspicious, because I cannot see a conversion from strings (what csv.reader produces) to floating point numbers.
Also your plot look suspicious, because the y tick labels are not sorted!
I decided to check if, by chance, Matplotlib tries to be smarter than it should...
import numpy as np
import matplotlib.pyplot as plt
# let's plot an array of strings, as I suppose you did,
# and see if Matplotlib doesn't like it, or ...
np.random.seed(20210719)
arr_of_floats = 80+10*np.random.rand(10)
arr_of_strings = np.array(["x = %6.3f"%round(x, 2) for x in arr_of_floats])
plt.plot(range(10), arr_of_strings)
plt.show()
Now, let's see what happens if we perform the conversion to floats
# for you it's simply: array(chamber_temperature, dtype=float)
arr_of_floats = np.array([s[4:] for s in arr_of_strings], dtype=float)
plt.plot(range(10), arr_of_floats)
plt.show()
Eventually, do not change axes' limits (etc etc) BEFORE plotting, but:
first, possibly organize your figure (figure size, subplots, etc)
second, plot your data,
third, adjust the details of the graph and
fourth and last, commit your work using plt.show().
Use
plt.ylim([bottom limit, top limit]) #like plt.ylim(84,86)
before your
plt.show()
that should work!
You are setting your x and y lims, as you have the equal sign.
You need to call them like a function (no equal sign).

Matplotlib how to dotplot variable number of points over time?

I'm trying to build an audiofingerprint algorithm like Shazam.
I have a variable length array of frequency point data like so:
[[69, 90, 172],
[6, 18, 24],
[6, 18],
[6, 18, 24, 42],
[]
...
I would like to dotplot it like a spectrogram sort of like this. My data doesn't explicitly have a time series axes but each row is a 0.1s slice of time. I am aware of plt.specgram.
np.repeat can create an accompanying array of x's. It needs an array of sizes to be calculated from the input values.
Here is an example supposing the x's are .1 apart (like in the post's description, but unlike the example image).
import numpy as np
import matplotlib.pyplot as plt
# ys = [[69, 90, 172], [6, 18, 24], [6, 18], [6, 18, 24, 42]]
ys = [np.random.randint(50, 3500, np.random.randint(2, 6)) for _ in range(30)]
sizes = [len(y) for y in ys]
xs = [np.repeat(np.arange(.1, (len(ys) + .99) / 10, .1), sizes)]
plt.scatter(xs, np.concatenate(ys), marker='x', color='blueviolet')
plt.show()

What does indexing the matplotlib axis do in a loop?

I saw a post on assigning the same colors across multiple pie plots in Matplotlib here
But there's something I don't understand about indexing the axis object.
Here's the code:
import numpy as np
import matplotlib.pyplot as plt
def mypie(slices,labels,colors):
colordict={}
for l,c in zip(labels,colors):
print l,c
colordict[l]=c
fig = plt.figure(figsize=[10, 10])
ax = fig.add_subplot(111)
pie_wedge_collection = ax.pie(slices, labels=labels, labeldistance=1.05)#, autopct=make_autopct(slices))
for pie_wedge in pie_wedge_collection[0]:
pie_wedge.set_edgecolor('white')
pie_wedge.set_facecolor(colordict[pie_wedge.get_label()])
titlestring = 'Issues'
ax.set_title(titlestring)
return fig,ax,pie_wedge_collection
slices = [37, 39, 39, 38, 62, 21, 15, 9, 6, 7, 6, 5, 4, 3]
cmap = plt.cm.prism
colors = cmap(np.linspace(0., 1., len(slices)))
labels = [u'TI', u'Con', u'FR', u'TraI', u'Bug', u'Data', u'Int', u'KB', u'Other', u'Dep', u'PW', u'Uns', u'Perf', u'Dep']
fig,ax,pie_wedge_collection = mypie(slices,labels,colors)
plt.show()
In the line: for pie_wedge in pie_wedge_collection[0] what does the index [0] do? The code doesn't work if I don't use it or use pie_wedge_collection[1]
Doesn't the ax object here only have one plot here? So I don't understand what the index is doing.
According to the Matplotlib documentation, pie() returns two or three lists:
A list of matplotlib.patches.Wedge
A list of matplotlib.text.Text labels
(conditionally) A list of matplotlib.text.Text data labels
Your code needs to manipulate the edge and face colors of the Wedge objects returned by pie(), which are in the first list (zero index) in the return value, pie_wedge_collection.

Categories

Resources