Labels in Plots - matplotlib

I am having some issues adding labels to the legend. For some reason matplotlib is ignoring the labels I create in the dataframe. Any help?
pandas version: 0.13.0
matplotlib version: 1.3.1
import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt
# Sample dataframe
d = {'date': [pd.to_datetime('1/1/2013'), pd.to_datetime('1/1/2014'), pd.to_datetime('1/1/2015')],
'number': [1,2,3],
'letter': ['A','B','C']}
df = pd.DataFrame(d)
####################
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(13, 10))
fig.subplots_adjust(hspace=2.0) ## Create space between plots
# Chart 1
df.plot(ax=axes[0], label='one')
# Chart 2
df.set_index('date')['number'].plot(ax=axes[1], label='two')
# add a little sugar
axes[0].set_title('This is the title')
axes[0].set_ylabel('the y axis')
axes[0].set_xlabel('the x axis')
axes[0].legend(loc='best')
axes[1].legend(loc='best');
The problem is that Chart 1 is returning the legend as "number" and I want it to say "one".

Will illustrate this for first axis. You may repeat for the second.
In [72]: fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(13, 10))
Get a reference to the axis
In [73]: ax=df.plot(ax=axes[0])
Get the legend
In [74]: legend = ax.get_legend()
Get the text of the legend
In [75]: text = legend.get_texts()[0]
Printing the current text of the legend
In [77]: text.get_text()
Out[77]: u'number'
Setting the desired text
In [78]: text.set_text("one")
Drawing to update
In [79]: plt.draw()
The following figure shows the changed legend for first axis. You may do the same for the other axis.
NB: IPython autocomplete helped a lot to figure out this answer!

Related

Add xticks within margins

I am trying create two plots that should have the same width when displayed in a row-wise fashion. I have noticed that adding xticks followed by tight_layout makes the plot (pcolormesh) decrease in width from increasing the x-margins. I would like to move the ticks in such a way that the x-margins are eliminated and both pcolormesh have the same width.
I have the following example:
import numpy as np, matplotlib.pyplot as plt
def plot(ticks=True):
fig, ax = plt.subplots(figsize=(6,1))
np.random.seed(42)
a = np.random.randn(1,6)
ax.pcolormesh(a)
plt.gca().invert_yaxis()
ax.xaxis.tick_top()
ax.set(yticklabels=[])
ax.tick_params(left=False, length=5)
if ticks:
ax.set_xticks([0, 3, 6])
else:
plt.axis('off')
plt.tight_layout()
plt.savefig(f'plot-{ticks}.png', dpi=300, bbox_inches='tight', pad_inches=0.0)
I get the following plots when running with and without the ticks:
The x-margins are not the same, which is more noticeable when increasing the font-size. How do I move the 3 label to right and the 6 label to the left to make both images have the same x-margins (0 margin)?
EDIT
Using the suggestion from Align specific x labels differently to each other? we have
import numpy as np, matplotlib.pyplot as plt
plt.rcParams.update({'font.size': 17})
fig, ax = plt.subplots(figsize=(6,1))
np.random.seed(42)
a = np.random.randn(1,6)
ax.pcolormesh(a)
plt.gca().invert_yaxis()
ax.xaxis.tick_top()
ax.set(yticklabels=[])
ax.tick_params(left=False, length=5)
# get list of x tick objects
xtick_objects = ax.xaxis.get_major_ticks()
xtick_objects[0].label1.set_horizontalalignment('left') # left align first tick
xtick_objects[-1].label1.set_horizontalalignment('right') # right align last tick
ax.set_xticks([0, 3, 6])
plt.tight_layout()
# plt.savefig(f'plot.png', dpi=300, bbox_inches='tight', pad_inches=0.0
plt.show()
which does not seem to change the alignment.

Plot multiple mplfinance plots sharing x axis

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]

how to increase space between bar and increase bar width in matplotlib

i am web-scraping a wikipedia table directly from wikipedia website and plot the table. i want to increase the bar width, add space between the bars and make all bars visible. pls how can i do? my code below
#########scrapping#########
html= requests.get("https://en.wikipedia.org/wiki/COVID-19_pandemic_in_Nigeria")
bsObj= BeautifulSoup(html.content, 'html.parser')
states= []
cases=[]
for items in bsObj.find("table",{"class":"wikitable sortable"}).find_all('tr')[1:37]:
data = items.find_all(['th',{"align":"left"},'td'])
states.append(data[0].a.text)
cases.append(data[1].b.text)
########Dataframe#########
table= ["STATES","CASES"]
tab= pd.DataFrame(list(zip(states,cases)),columns=table)
tab["CASES"]=tab["CASES"].replace('\n','', regex=True)
tab["CASES"]=tab["CASES"].replace(',','', regex=True)
tab['CASES'] = pd.to_numeric(tab['CASES'], errors='coerce')
tab["CASES"]=tab["CASES"].fillna(0)
tab["CASES"] = tab["CASES"].values.astype(int)
#######matplotlib########
x=tab["STATES"]
y=tab["CASES"]
plt.cla()
plt.locator_params(axis='y', nbins=len(y)/4)
plt.bar(x,y, color="blue")
plt.xticks(fontsize= 8,rotation='vertical')
plt.yticks(fontsize= 8)
plt.show()
Use pandas.read_html and barh
.read_html will read all tables tags from a website and return a list of dataframes.
barh will make horizontal instead of vertical bars, which is useful if there are a lot of bars.
Make the plot longer, if needed. In this case, (16.0, 10.0), increase 10.
I'd recommend using a log scale for x, because Lagos has so many cases compared to Kogi
This doesn't put more space between the bars, but the formatted plot is more legible with its increased dimensions and horizontal bars.
.iloc[:36, :5] removes some unneeded columns and rows from the dataframe.
import pandas as pd
import matplotlib.pyplot as plt
# url
url = 'https://en.wikipedia.org/wiki/COVID-19_pandemic_in_Nigeria'
# create dataframe list
dataframe_list = pd.read_html(url) # this is a list of all the tables at the url as dataframes
# get the dataframe from the list
df = dataframe_list[2].iloc[:36, :5] # you want the dataframe at index 2
# replace '-' with 0
df.replace('–', 0, inplace=True)
# set to int
for col in df.columns[1:]:
df[col] = df[col].astype('int')
# plot a horizontal bar
plt.rcParams['figure.figsize'] = (16.0, 10.0)
plt.style.use('ggplot')
p = plt.barh(width='Cases', y='State', data=df, color='purple')
plt.xscale('log')
plt.xlabel('Number of Cases')
plt.show()
Plot all the data in df
df.set_index('State', inplace=True)
plt.figure(figsize=(14, 14))
df.plot.barh()
plt.xscale('log')
plt.show()
4 subplots
State as index
plt.figure(figsize=(14, 14))
for i, col in enumerate(df.columns, 1):
plt.subplot(2, 2, i)
df[col].plot.barh(label=col, color='green')
plt.xscale('log')
plt.legend()
plt.tight_layout()
plt.show()

"panel barchart" in matplotlib

I would like to produce a figure like this one using matplotlib:
(source: peltiertech.com)
My data are in a pandas DataFrame, and I've gotten as far as a regular stacked barchart, but I can't figure out how to do the part where each category is given its own y-axis baseline.
Ideally I would like the vertical scale to be exactly the same for all the subplots and move the panel labels off to the side so there can be no gaps between the rows.
I haven't exactly replicated what you want but this should get you pretty close.
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
#create dummy data
cols = ['col'+str(i) for i in range(10)]
ind = ['ind'+str(i) for i in range(10)]
df = pd.DataFrame(np.random.normal(loc=10, scale=5, size=(10, 10)), index=ind, columns=cols)
#create plot
sns.set_style("whitegrid")
axs = df.plot(kind='bar', subplots=True, sharey=True,
figsize=(6, 5), legend=False, yticks=[],
grid=False, ylim=(0, 14), edgecolor='none',
fontsize=14, color=[sns.xkcd_rgb["brownish red"]])
plt.text(-1, 100, "The y-axis label", fontsize=14, rotation=90) # add a y-label with custom positioning
sns.despine(left=True) # get rid of the axes
for ax in axs: # set the names beside the axes
ax.lines[0].set_visible(False) # remove ugly dashed line
ax.set_title('')
sername = ax.get_legend_handles_labels()[1][0]
ax.text(9.8, 5, sername, fontsize=14)
plt.suptitle("My panel chart", fontsize=18)

How can I have each plot in matplotlib's `subplots` use a different axes?

So when I try to graph multiple subplots using pyplot.subplots I get something like:
How can I have:
Multiple independent axes for every subplot
Axes for every subplot
Overlay plots in every subplot axes using subplots. I tried to do ((ax1,ax2),(ax3,ax4)) = subplots and then do ax1.plot twice, but as a result, neither of the two showed.
Code for the picture:
import string
import matplotlib
matplotlib.use('WX')
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import numpy as np
from itertools import izip,chain
f,((ax1,ax2),(ax3,ax4)) = plt.subplots(2,2,sharex='col',sharey='row')
ax1.plot(range(10),2*np.arange(10))
ax2.plot(range(10),range(10))
ax3.plot(range(5),np.arange(5)*1000)
#pyplot.yscale('log')
#ax2.set_autoscaley_on(False)
#ax2.set_ylim([0,10])
plt.show()
Questions 1 & 2:
To accomplish this, explicitly set the subplots options sharex and sharey=False.
replace this line in the code for the desired results.
f, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, sharex=False, sharey=False)
Alternatively, those two options can be omitted altogether, as False is the default. (as noted by rubenvb below)
Question 3:
Here are two examples of adding secondary plots to two of the subplots:
(add this snippet before plt.show())
# add an additional line to the lower left subplot
ax3.plot(range(5), -1*np.arange(5)*1000)
# add a bar chart to the upper right subplot
width = 0.75 # the width of the bars
x = np.arange(2, 10, 2)
y = [3, 7, 2, 9]
rects1 = ax2.bar(x, y, width, color='r')
Don't tell it to share axes:
f, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
ax1.plot(range(10),2*np.arange(10))
ax2.plot(range(10),range(10))
ax3.plot(range(5),np.arange(5)*1000)
doc