I have a dataframe as below:
frame_id time_stamp pixels step
0 50 06:34:10 0.000000 0
1 100 06:38:20 0.000000 0
2 150 06:42:30 3.770903 1
3 200 06:46:40 3.312285 1
4 250 06:50:50 3.077356 0
5 300 06:55:00 2.862603 0
I want to draw two y-axes in one plot. One is for pixels. The other is for step. x-axis is time_stamp. I want the plot for step like the green line like this:
Here's an example that could help. Change d1 and d2 as per your variables and the respective labels as well.
import numpy as np
import matplotlib.pyplot as plt
rng = np.random.default_rng(seed=0)
d1 = rng.normal(loc=20, scale=5, size=200)
d2 = rng.normal(loc=30, scale=5, size=500)
fig, ax1 = plt.subplots(figsize=(9,5))
#create twin axes
ax2 = ax1.twinx()
ax1.hist([d1], bins=15, histtype='barstacked', linewidth=2,
alpha=0.7)
ax2.hist([d2], bins=15, histtype='step', linewidth=2,
alpha=0.7)
ax1.set_xlabel('Interval')
ax1.set_ylabel('d1 freq')
ax2.set_ylabel('d2 freq')
plt.show()
Getting the bar labels is not easy with the two types of histograms in the same plot using matplotlib.
bar_labels
Instead of histograms you could use bar plots to get the desired output. I have also added in a function to help get the bar labels.
import matplotlib.pyplot as plt
import numpy as np
time = ['06:34:10','06:38:20','06:42:30','06:46:40','06:50:50','06:55:00']
step = [0,0,1,1,0,0]
pixl = [0.00,0.00,3.77,3.31,3.077,2.862]
#function to add labels
def addlabels(x,y):
for i in range(len(x)):
plt.text(i, y[i], y[i], ha = 'center')
fig, ax1 = plt.subplots(figsize=(9,5))
#generate twin axes
ax2 = ax1.twinx()
ax1.step(time,step, 'k',where="mid",linewidth=1)
ax2.bar(time,pixl,linewidth=1)
addlabels(time,step)
addlabels(time,pixl)
ax1.set_xlabel('Time')
ax1.set_ylabel('Step')
ax2.set_ylabel('Pixels')
plt.show()
bar_plot
Related
I am trying to plot 5 charts one under the other with mplfinance.
This works:
for coin in coins:
mpf.plot(df_coins[coin], title=coin, type='line', volume=True, show_nontrading=True)
However each plot is a separate image in my Python Notebook cell output. And the x-axis labelling is repeated for each image.
I try to make a single figure containing multiple subplot/axis, and plot one chart into each axis:
from matplotlib import pyplot as plt
N = len(df_coins)
fig, axes = plt.subplots(N, figsize=(20, 5*N), sharex=True)
for i, ((coin, df), ax) in zip(enumerate(df_coins.items()), axes):
mpf.plot(df, ax=ax, title=coin, type='line', volume=True, show_nontrading=True)
This displays subfigures of the correct dimensions, however they are not getting populated with data. Axes are labelled from 0.0 to 1.0 and the title is not appearing.
What am I missing?
There are two ways to subplot. One is to set up a figure with mplfinance objects. The other way is to use your adopted matplotlib subplot to place it.
yfinace data
import matplotlib.pyplot as plt
import mplfinance as mpf
import yfinance as yf
tickers = ['AAPL','GOOG','TSLA']
data = yf.download(tickers, start="2021-01-01", end="2021-03-01", group_by='ticker')
aapl = data[('AAPL',)]
goog = data[('GOOG',)]
tsla = data[('TSLA',)]
mplfinance
fig = mpf.figure(style='yahoo', figsize=(12,9))
#fig.subplots_adjust(hspace=0.3)
ax1 = fig.add_subplot(3,1,1, sharex=ax3)
ax2 = fig.add_subplot(3,1,2, sharex=ax3)
ax3 = fig.add_subplot(3,1,3)
mpf.plot(aapl, type='line', ax=ax1, axtitle='AAPL', xrotation=0)
mpf.plot(goog, type='line', ax=ax2, axtitle='GOOG', xrotation=0)
mpf.plot(tsla, type='line', ax=ax3, axtitle='TSLA', xrotation=0)
ax1.set_xticklabels([])
ax2.set_xticklabels([])
matplotlib
N = len(tickers)
fig, axes = plt.subplots(N, figsize=(20, 5*N), sharex=True)
for df,t,ax in zip([aapl,goog,tsla], tickers, axes):
mpf.plot(df, ax=ax, axtitle=t, type='line', show_nontrading=True)# volume=True
In addition to the techniques mentioned by #r-beginners there is another technique that may work for you in the case where all plots share the same x-axis. That is to use mpf.make_addplot().
aps = []
for coin in coins[1:]:
aps.append(mpf.make_addplot(df_coins[coin]['Close'], title=coin, type='line'))
coin = coins[0]
mpf.plot(df_coins[coin],axtitle=coin,type='line',volume=True,show_nontrading=True,addplot=aps)
If you choose to do type='candle' instead of 'line', then change
df_coins[coin]['Close']
to simply
df_coins[coin]
I'd like to have two plots (a scatter and a bar) shown on the same figure, with the following layout:
| 0 | 1 | 2 | 3 |
But where 0 through 2 are filled with the first plot, and 3 is filled with the second. I've tried to use fig, ax = plt.subplots(1,4,figsize = (12, 10)) to create a 1x4 array of subplots, but when I call sns.scatterplot(..., ax=...), the ax argument is only able to accept one subplot label.
Is there a way, either in the subplot call or in the ax argument, to make a plot that is 75% of the width?
This is one way to do it using plt.subplots() by utilizing the keyword gridspec_kwdict, which takes dictionary that is passed to the GridSpec constructor used to create the grid on which the subplots are placed.
import numpy as np
from collections import Counter
import matplotlib.pyplot as plt
np.random.seed(123)
data = np.random.randint(0, 10, 100)
x, y = zip(*Counter(data).items())
fig, (ax1, ax2) = plt.subplots(1, 2, gridspec_kw={'width_ratios': [3, 1]},
figsize=(10, 4))
ax1.scatter(x, y)
ax2.bar(x, y)
plt.tight_layout()
I'm trying to get a line plot to be over the bar plot. But no matter what I do to change the zorder, it seems like it keeps the bar on top of the line. Nothing I do to try to change zorder seems to work. Sometimes the bar plot just doesn't show up if zorder is <= 0.
import pandas as pd
import matplotlib.pyplot as plt
def tail_plot(tail):
plt.figure()
#line plot
ax1 = incidence[incidence['actual_inc'] != 0].tail(tail).plot(x='date', y=['R_t', 'upper 95% CI', 'lower 95% CI'], color = ['b', '#808080', '#808080'])
ax1.set_zorder(2)
ax2 = ax1.twinx()
inc = incidence[incidence['actual_inc'] != 0]['actual_inc'].tail(tail).values
dates = incidence[incidence['actual_inc'] != 0]['date'].tail(tail).values
#bar plot
ax2.bar(dates, inc, color ='red', zorder=1)
ax2.set_zorder(1)
Keeps giving me this:
The problem with the approach in the post is that ax1 has a white background which totally occludes the plot of ax2. To solve this, the background color can be set to 'none'.
Note that the plt.figure() in the example code of the post creates an empty plot because the pandas plot creates its own new figure (as no ax is given explicitly).
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({f'curve {i}': 20 + np.random.normal(.1, .5, 30).cumsum() for i in range(1, 6)})
# line plot
ax1 = df.plot()
ax1.set_zorder(2)
ax1.set_facecolor('none')
ax2 = ax1.twinx()
# bar plot
x = np.arange(30)
ax2.bar(x, np.random.randint(7 + x, 2 * x + 10), color='red', zorder=1)
ax2.set_zorder(1)
plt.show()
I am doing a PCA, and have 10 components. I would like to plot the first 3 components and colour according to their group type.
from mpl_toolkits.mplot3d import Axes3D
df=pd.DataFrame(np.random.rand(30,20))
grp=round(pd.DataFrame(np.random.rand(30)*10),0)
df['grp']=grp
fig = plt.figure(figsize=(12, 9))
ax = Axes3D(fig)
y = df.iloc[:,1]
x = df.iloc[:,0]
z = df.iloc[:,2]
c = df['grp']
ax.scatter(x,y,z, c=c, cmap='coolwarm')
plt.title('First 3 Principal Components')
ax.set_ylabel('PC2')
ax.set_xlabel('PC1')
ax.set_zlabel('PC3')
plt.legend()
this works, but unfortunately does not show a legend, nor I believe all of the possible groups.
Any suggestions
Check out pandas groupby, grouping you data by groups and plot your groups individually:
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(12, 9))
ax = Axes3D(fig)
for grp_name, grp_idx in df.groupby('grp').groups.items():
y = df.iloc[grp_idx,1]
x = df.iloc[grp_idx,0]
z = df.iloc[grp_idx,2]
ax.scatter(x,y,z, label=grp_name) # this way you can control color/marker/size of each group freely
ax.scatter(*df.iloc[grp_idx, [0, 1, 2]].T.values, label=grp_name) # if you want to do everything in one line, lol
ax.legend()
You can try adding a colorbar:
# note the difference
cb = ax.scatter(x,y,z, c=c, cmap='coolwarm')
plt.title('First 3 Principal Components')
ax.set_ylabel('PC2')
ax.set_xlabel('PC1')
ax.set_zlabel('PC3')
# and here we add a colorbar
plt.colorbar(cb)
plt.legend()
I have a pandas series containing numbers ranging between 0 and 100. I want to visualise it in a horizontal bar consisting of 3 main colours.
I have tried using seaborn but all I can get is a heatmap matrix. I have also tried the below code, which is producing what I need but not in the way I need it.
x = my_column.values
y = x
t = x
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.scatter(x, y, c=t, cmap='brg')
ax2.scatter(x, y, c=t, cmap='brg')
plt.show()
What I'm looking for is something similar to the below figure, how can I achieve that using matplotlib or seaborn?
The purpose of this is not quite clear, however, the following would produce an image like the one shown in the question:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
x = np.linspace(100,0,101)
fig, ax = plt.subplots(figsize=(6,1), constrained_layout=True)
cmap = LinearSegmentedColormap.from_list("", ["limegreen", "gold", "crimson"])
ax.imshow([x], cmap=cmap, aspect="auto",
extent=[x[0]-np.diff(x)[0]/2, x[-1]+np.diff(x)[0]/2,0,1])
ax.tick_params(axis="y", left=False, labelleft=False)
plt.show()