I'm trying to produce a stacked set of waveform plots to include in a paper, and my desired font is Helvetica, which is applied to the x-axis values and labels but not to the y-axis values. An additional issue I'm having is the repeated x-axis labels, as I only wish to have time labelled on the bottom plot. Here is my code:
from matplotlib import rc
import matplotlib.pyplot as plt
rc('font', **{'family': 'sans-serif', 'sans-serif': ['Helvetica']})
rc('text', usetex=True)
ref, sr = librosa.load(r"C:\Users\...\ref_4_dry.wav", mono=False, duration=10, sr=44100)
wn, sr = librosa.load(r"C:\Users\...\wn_4_dry.wav", mono=False, duration=10, sr=44100)
mwn, sr = librosa.load(r"C:\Users\...\mwn_4_dry.wav", mono=False, duration=10, sr=44100)
fig, ax = plt.subplots(nrows=3, sharex=True, figsize=(15, 15))
librosa.display.waveshow(ref, sr=sr, ax=ax[0])
librosa.display.waveshow(wn, sr=sr, ax=ax[1])
librosa.display.waveshow(mwn, sr=sr, ax=ax[2])
Here is an image of the issue I'm having (the y-axis font seems to be reverting to Computer Modern or some other standard font):
Related
I am a novice to python. I was trying to plot 2 D color plot using imshow(). Here, x axis is the time scale, yaxis is the energy and the colorbar z axis is the differential energy flux. When i plot somehow the y axis do not correspond to the actual value. I had tried using contourf as well as plotly heatmap. However I find though the results come correctly it does not have the same visual impact as imshow.
import matplotlib.pyplot as plt
from matplotlib import colors
import numpy as np
import matplotlib.dates as mdates
from mpl_toolkits.axes_grid1 import make_axes_locatable
import datetime as dt
x_lims = list(map(dt.datetime.utcfromtimestamp, [1266050102.1784432, 1266054264.5317998]))
x_lims = mdates.date2num(x_lims)
y1 = [3.1209615e+04, 2.6360914e+04, 2.0025836e+04, 1.5213330e+04, 1.1557158e+04,
8.7796689e+03, 6.6698813e+03, 5.0668237e+03, 3.8490525e+03, 2.9246511e+03,
2.2212300e+03, 1.6873538e+03, 1.2815887e+03, 9.7440747e+02, 7.3961621e+02,
5.6149872e+02, 4.2719626e+02, 3.2432623e+02, 2.4669749e+02, 1.8716624e+02,
1.4239874e+02, 1.0858500e+02, 8.2391251e+01, 6.2388748e+01, 4.7625000e+01,
3.6195000e+01, 2.7622499e+01, 2.0478750e+01, 1.5716249e+01, 1.2382500e+01,
9.0487499e+00, 7.1437497e+00]
y = np.array(y1)
y_lims = [y.min(), y.max()]
extent_lims = [x_lims[0], x_lims[1], y_lims[0], y_lims[1]]
z = flux_elec.T
fig, ax = plt.subplots()
im = ax.imshow(z, interpolation='none', extent=extent_lims, cmap='jet', aspect='auto')
date_format = mdates.DateFormatter('%H:%M')
ax.set_yscale('log')
ax.xaxis.set_major_formatter(date_format)
ax.xaxis_date()
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im, cax=cax, label="diff. en. flux")
[enter image description here](https://i.stack.imgur.com/Op1X7.png)
In this the high energy flux (8) should finish before 100 but its extending till 5000. I am unable to locate the error.
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]
So currently learning how to import data and work with it in matplotlib and I am having trouble even tho I have the exact code from the book.
This is what the plot looks like, but my question is how can I get it where there is no white space between the start and the end of the x-axis.
Here is the code:
import csv
from matplotlib import pyplot as plt
from datetime import datetime
# Get dates and high temperatures from file.
filename = 'sitka_weather_07-2014.csv'
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
#for index, column_header in enumerate(header_row):
#print(index, column_header)
dates, highs = [], []
for row in reader:
current_date = datetime.strptime(row[0], "%Y-%m-%d")
dates.append(current_date)
high = int(row[1])
highs.append(high)
# Plot data.
fig = plt.figure(dpi=128, figsize=(10,6))
plt.plot(dates, highs, c='red')
# Format plot.
plt.title("Daily high temperatures, July 2014", fontsize=24)
plt.xlabel('', fontsize=16)
fig.autofmt_xdate()
plt.ylabel("Temperature (F)", fontsize=16)
plt.tick_params(axis='both', which='major', labelsize=16)
plt.show()
There is an automatic margin set at the edges, which ensures the data to be nicely fitting within the axis spines. In this case such a margin is probably desired on the y axis. By default it is set to 0.05 in units of axis span.
To set the margin to 0 on the x axis, use
plt.margins(x=0)
or
ax.margins(x=0)
depending on the context. Also see the documentation.
In case you want to get rid of the margin in the whole script, you can use
plt.rcParams['axes.xmargin'] = 0
at the beginning of your script (same for y of course). If you want to get rid of the margin entirely and forever, you might want to change the according line in the matplotlib rc file:
axes.xmargin : 0
axes.ymargin : 0
Example
import seaborn as sns
import matplotlib.pyplot as plt
tips = sns.load_dataset('tips')
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
tips.plot(ax=ax1, title='Default Margin')
tips.plot(ax=ax2, title='Margins: x=0')
ax2.margins(x=0)
Alternatively, use plt.xlim(..) or ax.set_xlim(..) to manually set the limits of the axes such that there is no white space left.
If you only want to remove the margin on one side but not the other, e.g. remove the margin from the right but not from the left, you can use set_xlim() on a matplotlib axes object.
import seaborn as sns
import matplotlib.pyplot as plt
import math
max_x_value = 100
x_values = [i for i in range (1, max_x_value + 1)]
y_values = [math.log(i) for i in x_values]
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
sn.lineplot(ax=ax1, x=x_values, y=y_values)
sn.lineplot(ax=ax2, x=x_values, y=y_values)
ax2.set_xlim(-5, max_x_value) # tune the -5 to your needs
I have the following heatmap:
I've broken up the category names by each capital letter and then capitalised them. This achieves a centering effect across the labels on my x-axis by default which I'd like to replicate across my y-axis.
yticks = [re.sub("(?<=.{1})(.?)(?=[A-Z]+)", "\\1\n", label, 0, re.DOTALL).upper() for label in corr.index]
xticks = [re.sub("(?<=.{1})(.?)(?=[A-Z]+)", "\\1\n", label, 0, re.DOTALL).upper() for label in corr.columns]
fig, ax = plt.subplots(figsize=(20,15))
sns.heatmap(corr, ax=ax, annot=True, fmt="d",
cmap="Blues", annot_kws=annot_kws,
mask=mask, vmin=0, vmax=5000,
cbar_kws={"shrink": .8}, square=True,
linewidths=5)
for p in ax.texts:
myTrans = p.get_transform()
offset = mpl.transforms.ScaledTranslation(-12, 5, mpl.transforms.IdentityTransform())
p.set_transform(myTrans + offset)
plt.yticks(plt.yticks()[0], labels=yticks, rotation=0, linespacing=0.4)
plt.xticks(plt.xticks()[0], labels=xticks, rotation=0, linespacing=0.4)
where corr represents a pre-defined pandas dataframe.
I couldn't seem to find an align parameter for setting the ticks and was wondering if and how this centering could be achieved in seaborn/matplotlib?
I've adapted the seaborn correlation plot example below.
from string import ascii_letters
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
sns.set_theme(style="white")
# Generate a large random dataset
rs = np.random.RandomState(33)
d = pd.DataFrame(data=rs.normal(size=(100, 7)),
columns=['Donald\nDuck','Mickey\nMouse','Han\nSolo',
'Luke\nSkywalker','Yoda','Santa\nClause','Ronald\nMcDonald'])
# Compute the correlation matrix
corr = d.corr()
# Generate a mask for the upper triangle
mask = np.triu(np.ones_like(corr, dtype=bool))
# Set up the matplotlib figure
f, ax = plt.subplots(figsize=(11, 9))
# Generate a custom diverging colormap
cmap = sns.diverging_palette(230, 20, as_cmap=True)
# Draw the heatmap with the mask and correct aspect ratio
sns.heatmap(corr, mask=mask, cmap=cmap, vmax=.3, center=0,
square=True, linewidths=.5, cbar_kws={"shrink": .5})
for i in ax.get_yticklabels():
i.set_ha('right')
i.set_rotation(0)
for i in ax.get_xticklabels():
i.set_ha('center')
Note the two for sequences above. These get the label and then set the horizontal alignment (You can also change the vertical alignment (set_va()).
The code above produces this:
The scatter plot generated for the piece of code below using seaborn is as follows.
ax = sns.scatterplot(x="Param_1",
y="Param_2",
hue="Process", style='Item', data=df,
s=30, legend='full')
I wanted to get rid of color legends (for process) in circle as circles also denote data for Item 'One'. What would be the best way to present the colors legends for Process without making a discrepancy with shapes used for Item.
You can create so-called proxy artists and use them as legend symbols.
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
fig,(ax1,ax2) = plt.subplots(ncols=2)
tips = sns.load_dataset("tips")
hue = "day"
style = "time"
sns.scatterplot(x="total_bill", y="tip", hue=hue, style=style, data=tips, ax=ax1)
ax1.set_title("Default Legend")
sns.scatterplot(x="total_bill", y="tip", hue=hue, style=style, data=tips, ax=ax2)
ax2.set_title("Custom Legend")
handles, labels = ax2.get_legend_handles_labels()
for i,label in enumerate(labels):
if label == hue:
continue
if label == style:
break
handles[i] = mpatches.Patch(color=handles[i].get_fc()[0])
ax2.legend(handles, labels)