Matplotlib align uneven number of subplots - python

I want to plot 11 figures using subplots. My idea is to have 2 rows: 6 plots on the first, 5 on the second. I use the following code.
import matplotlib.pyplot as plt
import pandas as pd
fig, axes = plt.subplots(2, 6, figsize=(30, 8))
fig.tight_layout(h_pad=6, w_pad=6)
x = 0
y = 0
for i in range(0, 11):
data = [[1, i*1], [2, i*2*2], [3, i*3*3]]
df = pd.DataFrame(data, columns = ['x', 'y'])
df.plot('x', ['y'], ax=axes[x,y])
y += 1
if y > 5:
y = 0
x += 1
fig.delaxes(ax=axes[1,5])
This works, but the bottom row is not aligned to the center, which makes the result a bit ugly. I want the figures to all be of the same size, so I cannot extend the last one to make everything even.
My question: how do I align the second row to be centered such that the full picture is symmetrical?

You could use gridspec dividing each row into 12 partitions and recombining them pairswise:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import pandas as pd
fig = plt.figure(figsize=(12, 5))
gs = gridspec.GridSpec(2, 12)
for i in range(0, 11):
if i < 6:
ax = plt.subplot(gs[0, 2 * i:2 * i + 2])
else:
ax = plt.subplot(gs[1, 2 * i - 11:2 * i + 2 - 11])
data = [[1, i * 1], [2, i * 2 * 2], [3, i * 3 * 3]]
df = pd.DataFrame(data, columns=['x', 'y'])
df.plot('x', 'y', ax=ax)
plt.tight_layout()
plt.show()

Related

Separate bar in chart

I would like to show in every bin of the histogram, the 3 bars separated, so that it does not overlap. My code is this:
face = io.imread('images/face.png')
red_chanel = face[:,:,0]
green_chanel = face[:,:,1]
blue_chanel = face[:,:,2]
red_chanel = red_chanel.astype('float')
green_chanel = green_chanel.astype('float')
blue_chanel = blue_chanel.astype('float')
face = face.astype('float')
fig, ax1 = plt.subplots(ncols = 1, figsize = (20, 5))
hstred=exposure.histogram(red_chanel, nbins=28)
hstgreen=exposure.histogram(green_chanel, nbins=28)
hstblue=exposure.histogram(blue_chanel, nbins=28)
ax1.bar(list(range(28)), hstred[0], align='edge')
ax1.bar(list(range(28)), hstgreen[0], align='edge')
ax1.bar(list(range(28)), hstblue[0], align='edge')
plt.show()
How can I separate the bars?
I think you can shift the x-axis for 2nd and 3rd barplot and play with bar width a little. In the end, change the xticks.
import numpy as np
ax1.bar(np.arange(28), hstred[0], align='edge', width=0.3)
#shifting the xaxis
ax1.bar(np.arange(28)+0.3, hstgreen[0], align='edge', width=0.3)
ax1.bar(np.arange(28)+0.6, hstblue[0], align='edge', width=0.3)
plt.xticks(np.arange(0,28)+0.3, np.arange(0,28)) #resetting the ticks
Here is an example:
x1 = [1, 2, 3, 4, 5]
y1 = [1, 2, 3, 5, 6]
y2 = [4, 4, 2, 2, 2]
y3 = [3, 4, 6, 7, 8]
fig,ax = plt.subplots()
ax.bar(x1,y1,width=0.3)
ax.bar(np.array(x1)+0.3,y2,width=0.3)
ax.bar(np.array(x1)+0.6,y3,width=0.3)
plt.xticks(np.arange(0,6)+0.3, np.arange(0,6))
plt.show()
Output:

Plotting multiple columns of different sizes with Pandas

I'm fairly new to Pandas, but typically what I do with data (when all columns are of equal sizes), I build np.zeros(count) matrices, then use a for loop to populate the data from a text file (np.genfromtxt()) to do my graphing and analysis in matplotlib.
However, I am now trying to implement similar analysis with columns of different sizes on the same plot from a CSV file.
For instance:
data.csv:
A B C D E F
1 2 3 4 5 6
2 3 4 5 6 7
3 4 5 6
4 5
df = pandas.read_csv('data.csv')
ax = df.plot(x = 'A', y = 'B')
df.plot(x = 'C', y = 'D', ax = ax)
df.plot(x = 'E', y = 'F', ax = ax)
This code plots the first two on the same graph, but the rest of the information is lost (and there are a lot more columns of mismatched sizes, but the x/y columns I am plotting are the all the same size).
Is there an easier way to do all of this? Thanks!
Here is how you could generalize your solution :
I edited my answer to add an error handling. If you have a lonely last column, it'll still work.
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
data = {
'A' : [1, 2, 3, 4],
'B' : [2, 3, 4, 5],
'C' : [3, 4, 5, np.nan],
'D' : [4, 5, 6, np.nan],
'E' : [5, 6, np.nan, np.nan],
'F' : [6, 7, np.nan, np.nan]
}
df = pd.DataFrame(data)
def Chris(df):
ax = df.plot(x='A', y='B')
df.plot(x='C', y='D', ax=ax)
df.plot(x='E', y='F', ax=ax)
plt.show()
def IMCoins(df):
fig, ax = plt.subplots()
try:
for idx in range(0, df.shape[1], 2):
df.plot(x = df.columns[idx],
y = df.columns[idx + 1],
ax= ax)
except IndexError:
print('Index Error: Log the error.')
plt.show()
Chris(df)
IMCoins(df)

Dynamic treshold line in a bar chart

I have a stacked bar char where I want to add a dynamic threshold line. The threshold is calculated via a simple formular (90% of each specific value)
Graphic attached. The green line is what I am looking for. Looking forward for any idea how to approach this problem.
Here is what I came up with:
The idea was to have a continuous segment of Xs projected with a constant y value with a 0.5 excess before and after:
import numpy as np
import matplotlib.pyplot as plt
groups = 9
X = list(range(1, groups))
y = [1, 1, 2, 2, 1, 2, 1, 1]
threshold_interval_x = np.arange(min(X) - 0.5, max(X) + 0.5, 0.01).tolist()
threshold_y = []
for y_elt in y:
for i in range(0, int(len(threshold_interval_x) / (groups - 1))):
threshold_y.append(y_elt * 0.9)
plt.bar(X, y, width=0.4, align='center', color='yellow')
plt.plot(threshold_interval_x, threshold_y, color='green')
labels_X = ['PD', 'PZV', 'PP', 'FW', 'BA', 'IA', 'EA', 'NA']
plt.xticks(X, labels_X, rotation='horizontal')
plt.show()
And here's the output:
You could use matplotlibs step-function for this:
import pandas as pd
import matplotlib.pyplot as plt
supposed your data is structured like this:
df = pd.DataFrame({'In': [1, 1, 1, 2 , 0, 2, 0, 0], 'Out': [0, 0, 1, 0, 1, 0, 1, 1]}, index=['PD', 'PZV', 'PP', 'FW', 'BA', 'IA', 'EA', 'NA'])
In Out
PD 1 0
PZV 1 0
PP 1 1
FW 2 0
BA 0 1
IA 2 0
EA 0 1
NA 0 1
Then plotting the bars would be
df.plot(kind='bar', stacked=True, rot=0, color=['gold', 'beige'])
and plotting the threshold line at 90% of the sum would be
plt.step(df.index, df.sum(1) * .9, 'firebrick', where='mid', label = 'Ziel: 90%')
add legend:
plt.legend()
leads to:

Pandas Dataframe plot rows as x values and column header as y values

I have a Pandas DataFrame with displacements for different times (rows) and specific vertical locations (columns names). The goal is to plot the displacements (x axis) for the vertical location (y axis) for a given time (series).
According to the next example (time = 0, 1, 2, 3, 4 and vertical locations = 0.5, 1.5, 2.5, 3.5), how can the displacements be plotted for the times 0 and 3?
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(88)
df = pd.DataFrame({
'time': np.arange(0, 5, 1),
'0.5': np.random.uniform(-1, 1, size = 5),
'1.5': np.random.uniform(-2, 2, size = 5),
'2.5': np.random.uniform(-3, 3, size = 5),
'3.5': np.random.uniform(-4, 4, size = 5),
})
df = df.set_index('time')
You can filter your dataframe to only contain the desired rows. Either by using the positional index
filtered = df.iloc[[0,3],:]
or by using the actualy index of the dataframe,
filtered = df.iloc[(df.index == 3) | (df.index == 0),:]
You can then plot a scatter plot like this:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(88)
df = pd.DataFrame({
'time': np.arange(0, 5, 1),
'0.5': np.random.uniform(-1, 1, size = 5),
'1.5': np.random.uniform(-2, 2, size = 5),
'2.5': np.random.uniform(-3, 3, size = 5),
'3.5': np.random.uniform(-4, 4, size = 5),
})
df = df.set_index('time')
filtered_df = df.iloc[[0,3],:]
#filtered_df = df.iloc[(df.index == 3) | (df.index == 0),:]
loc = list(map(float, df.columns))
fig, ax = plt.subplots()
for row in filtered_df.iterrows():
ax.scatter(row[1], loc, label=row[1].name)
plt.legend()
plt.show()

matplotlib pyplot: subplot size

If I plot a single graph as below, it will be of size (x * y).
import matplotlib.pyplot as plt
plt.plot([1, 2], [1, 2])
However, if I plot 3 sub-graphs in the same row, each of them will be of size ((x / 3) * y).
fig, ax = plt.subplots(1, 3, sharey = True)
for i in range(3):
ax[i].plot([1, 2], [1, 2])
How can I obtain these 3 subplots, each of which is of size (x * y)?
The figure object has a default size that does not know about the number of subplots. You can change the figure size when you make the figure to suit your needs though.
import matplotlib.pyplot as plt
nx = 3
ny = 1
dxs = 8.0
dys = 6.0
fig, ax = plt.subplots(ny, nx, sharey = True, figsize=(dxs*nx, dys*ny) )
for i in range(nx):
ax[i].plot([1, 2], [1, 2])

Categories