Increase space between secondary y axis and x axis? - python

I have plotted a graph with two y-axes with python. However, I would like to have more space between the two lines, with the secondary y-axes on the top of the graph.
here's my code:
x = data['Data'].tolist()
y = data['Excess Return'].tolist()
z=data['EPU shock'].tolist()
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
curve1 = ax1.plot(x, y, label='Excess Return', color='r')
curve2 = ax2.plot(x, z, label='EPU shock', color='b')
lines_1, labels_1 = ax1.get_legend_handles_labels()
lines_2, labels_2 = ax2.get_legend_handles_labels()
lines = lines_1 + lines_2
labels = labels_1 + labels_2
ax1.legend(lines, labels, loc="lower center", borderaxespad=-5, ncol=2)
plt.title("European Union")
plt.show()
Output:
but I would like to have something like this:

Would a two-subplots setup work for you?
import matplotlib.pyplot as plt
import numpy as np
# Dummy data.
x = np.arange(2000, 2020, 1)
y1 = np.sin(x)
y2 = np.cos(x/2)
# We create a two-subplots figure and hide the boundary between the two Axes.
fig, (ax1, ax_temporary) = plt.subplots(2, 1)
ax2 = ax_temporary.twinx()
for spine in (ax1.spines["bottom"], ax_temporary.spines["top"], ax2.spines["top"]):
spine.set_visible(False)
ax1.xaxis.set_visible(False)
ax_temporary.yaxis.set_visible(False)
fig.subplots_adjust(hspace=0) # No space left!
# Create curves and legend.
curve1, = ax1.plot(x, y1, label='Excess Return', color='r')
curve2, = ax2.plot(x, y2, label='EPU shock', color='b')
lines_1, labels_1 = ax1.get_legend_handles_labels()
lines_2, labels_2 = ax2.get_legend_handles_labels()
lines = lines_1 + lines_2
labels = labels_1 + labels_2
ax2.legend(lines, labels, loc="lower center", borderaxespad=-5, ncol=2) # Legend on ax2 instead of ax1.
ax1.set_title("European Union")
fig.show()

Does it suit you to to adjust the limits?
fig, ax1 = plt.subplots()
ax2 = ax1.twinx() # open second y-axis
line1, = ax1.plot([0, 1, 2], [0, 1, 2], "b-", label="Line 1")
line2, = ax2.plot([0, 1, 2,], [10, 13, 12], "r-", label="Line 2")
# set limits
ax2.set_ylim( (-10,14) )
plt.show()

Related

Problem with minor thicks and color bar in matplotlib

This is cod for plotting.
Here I have two problems.
import matplotlib
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#### part where data are loaded and defined######
tab1 = pd.read_table("tab1.txt", delim_whitespace=True)
tab2 = pd.read_table("tab2.txt", delim_whitespace=True)
delen = (tab1['val2'] / tab1['val3']) *10**9
dist = tab1['val1']
size = abs(tab1['val4'])
m_Es_S0s = tab2['m1'][tab2['#type']==1]
r_Es_S0s = tab2['r1'][tab2['#type']==1]
m_dEs_dS0s = tab2['m1'][tab2['#type']==2]
r_dEs_dS0s = tab2['r1'][tab2['#type']==2]
m_dSphs = tab2['m1'][tab2['#type']==3]
r_dSphs = tab2['r1'][tab2['#type']==3]
m_Nuclear_SC = tab2['m1'][tab2['#type']==4]
r_Nuclear_SC = tab2['r1'][tab2['#type']==4]
m_GCs_UCDs_cEs = tab2['m1'][tab2['#type']==5]
r_GCs_UCDs_cEs = tab2['r1'][tab2['#type']==5]
m_YMCs = tab2['m1'][tab2['#type']==7]
r_YMCs = tab2['r1'][tab2['#type']==7]
#####part related to figure #########
fig1 = plt.figure(figsize=(10,8),dpi=100)
ax = plt.subplot()
ax.tick_params(axis='both', which='both', direction="in")
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.xscale('log')
plt.yscale('log')
plt.scatter(delen ,delen/(2*3.141592653*size**2), marker='o', s=80, c=dist, cmap='Greys_r', alpha=0.9, norm=matplotlib.colors.LogNorm(), edgecolors='darkorchid', linewidth=0.5)
a1=plt.scatter(m_Es_S0s ,m_Es_S0s/(2*3.141592653*r_Es_S0s**2), marker='o', facecolors='none', edgecolors='mediumblue', linewidth=0.5, s=20)
a2=plt.scatter(m_dEs_dS0s ,m_dEs_dS0s/(2*3.141592653*r_dEs_dS0s**2), marker='o', facecolors='none', edgecolors='lightgreen', linewidth=0.5, s=20)
#a3=plt.scatter(m_dSphs ,m_dSphs/(2*3.141592653*r_dSphs**2), marker='o', facecolors='none', edgecolors='red', linewidth=0.5, s=20)
a4=plt.scatter(m_Nuclear_SC ,m_Nuclear_SC/(2*3.141592653*r_Nuclear_SC**2), marker='o', facecolors='none', edgecolors='dodgerblue', linewidth=0.8, s=20)
#a5=plt.scatter(m_GCs_UCDs_cEs ,m_GCs_UCDs_cEs/(2*3.141592653*r_GCs_UCDs_cEs**2), marker='o', facecolors='none', edgecolors='dimgrey', linewidth=0.5, s=20)
a6=plt.scatter(m_YMCs ,m_YMCs/(2*3.141592653*r_YMCs**2), marker='o', facecolors='none', edgecolors='olive', linewidth=0.7, s=20)
plt.clim(1.8,6.8)
cb = plt.colorbar(pad=0.004)
cb.set_label(label='dist', size='medium', weight='bold')
cb.ax.tick_params(labelsize='large',direction='in')
plt.ylabel('yaxis', fontsize=18)
plt.xlabel('xaxis', fontsize=18)
plt.show()
Resulting plot looks like this:
But, after uncommenting a3 and a5 (so, including more data points on the plot) I am losing all minor ticks on my plot. Figure looks like this
This is first problem why I am losing minor ticks I would like to keep them. Also I would like to keep all markers .... 10^5,10^6,10^7 ......
Another problem is that color bar does not change color. You can notice that my cmap='Greys_r' and points on the plot are ok, but color bar keeps viridis all the time.
How to change color bar to Greys_r?
Tab1 and Tab2 are here:
https://www.dropbox.com/s/gwj72blzallqjl5/tab1.txt?dl=0
https://www.dropbox.com/s/mj4fr8hetsb45eo/tab2.txt?dl=0
Try this, it seems to work.
import matplotlib
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#### part where data are loaded and defined######
tab1 = pd.read_table("tab1.txt", delim_whitespace=True)
tab2 = pd.read_table("tab2.txt", delim_whitespace=True)
delen = (tab1['val2'] / tab1['val3']) *10**9
dist = tab1['val1']
size = abs(tab1['val4'])
m_Es_S0s = tab2['m1'][tab2['#type']==1]
r_Es_S0s = tab2['r1'][tab2['#type']==1]
m_dEs_dS0s = tab2['m1'][tab2['#type']==2]
r_dEs_dS0s = tab2['r1'][tab2['#type']==2]
m_dSphs = tab2['m1'][tab2['#type']==3]
r_dSphs = tab2['r1'][tab2['#type']==3]
m_Nuclear_SC = tab2['m1'][tab2['#type']==4]
r_Nuclear_SC = tab2['r1'][tab2['#type']==4]
m_GCs_UCDs_cEs = tab2['m1'][tab2['#type']==5]
r_GCs_UCDs_cEs = tab2['r1'][tab2['#type']==5]
m_YMCs = tab2['m1'][tab2['#type']==7]
r_YMCs = tab2['r1'][tab2['#type']==7]
#####part related to figure #########
fig1 = plt.figure(figsize=(10,8),dpi=100)
ax = plt.subplot()
ax.tick_params(axis='both', which='both', direction="in")
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.xscale('log')
plt.yscale('log')
cc = plt.scatter(delen ,delen/(2*3.141592653*size**2), marker='o', s=80, c=dist, cmap='Greys_r', alpha=0.9, norm=matplotlib.colors.LogNorm(), edgecolors='darkorchid', linewidth=0.5)
a1=plt.scatter(m_Es_S0s ,m_Es_S0s/(2*3.141592653*r_Es_S0s**2), marker='o', facecolors='none', edgecolors='mediumblue', linewidth=0.5, s=20)
a2=plt.scatter(m_dEs_dS0s ,m_dEs_dS0s/(2*3.141592653*r_dEs_dS0s**2), marker='o', facecolors='none', edgecolors='lightgreen', linewidth=0.5, s=20)
a3=plt.scatter(m_dSphs ,m_dSphs/(2*3.141592653*r_dSphs**2), marker='o', facecolors='none', edgecolors='red', linewidth=0.5, s=20)
a4=plt.scatter(m_Nuclear_SC ,m_Nuclear_SC/(2*3.141592653*r_Nuclear_SC**2), marker='o', facecolors='none', edgecolors='dodgerblue', linewidth=0.8, s=20)
a5=plt.scatter(m_GCs_UCDs_cEs ,m_GCs_UCDs_cEs/(2*3.141592653*r_GCs_UCDs_cEs**2), marker='o', facecolors='none', edgecolors='dimgrey', linewidth=0.5, s=20)
a6=plt.scatter(m_YMCs ,m_YMCs/(2*3.141592653*r_YMCs**2), marker='o', facecolors='none', edgecolors='olive', linewidth=0.7, s=20)
plt.clim(1.8,6.8)
cb = plt.colorbar(cc,pad=0.004)
cb.set_label(label='dist', size='medium', weight='bold')
#cb.ax.tick_params(labelsize='large',direction='in')
import matplotlib.ticker
## set y ticks
y_major = matplotlib.ticker.LogLocator(base = 10, numticks = 15)
ax.yaxis.set_major_locator(y_major)
y_minor = matplotlib.ticker.LogLocator(base = 10, subs = np.arange(1.0, 10.0) * 0.1, numticks = 20)
ax.yaxis.set_minor_locator(y_minor)
ax.yaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())
x_major = matplotlib.ticker.LogLocator(base = 10, numticks = 15)
ax.xaxis.set_major_locator(x_major)
x_minor = matplotlib.ticker.LogLocator(base = 10, subs = np.arange(1.0, 10.0) * 0.1, numticks = 20)
ax.xaxis.set_minor_locator(x_minor)
ax.xaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())
plt.ylabel('yaxis', fontsize=18)
plt.xlabel('xaxis', fontsize=18)
#plt.savefig("out1.png")
plt.show()
Output fig is here.
enter image description here

Multiple seaborn pointplots not showing the right color on the legend

I have three point plot i'm trying to chart and show a legend. The colors do not match the colors called out in the plots. I tried using the solution from this post, but that did not work.
Here is the code I'm using:
fig, ax = plt.subplots()
a = sns.pointplot(x=l[1:], y = np.exp(model_m.params[1:]), label = 'factor',
ax = ax, color = 'green')
b = sns.pointplot(x=l[1:], y = np.exp(model_m.conf_int()[1:][:,1]),
ax = ax, label = 'conf_int+', color = 'red')
c = sns.pointplot(x=l[1:], y = np.exp(model_m.conf_int()[1:][:,0]),
ax = ax, label = 'conf_int-', color = 'blue')
plt.title('Model M Discrete')
ax.legend(labels = ['factor', 'conf_inf+', 'conf_inf-'],
title = 'legend')
Here is what it produces:
The easiest solution would be to use sns.lineplot instead of sns.pointplot:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
fig, ax = plt.subplots()
x = np.arange(10)
sns.lineplot(x=x, y=1 + np.random.rand(10).cumsum(),
ax=ax, label='factor', color='green', marker='o')
sns.lineplot(x=x, y=2 + np.random.rand(10).cumsum(),
ax=ax, label='conf_int+', color='red', marker='o')
sns.lineplot(x=x, y=3 + np.random.rand(10).cumsum(),
ax=ax, label='conf_int-', color='blue', marker='o')
ax.set_title('Model M Discrete')
ax.legend(title='legend')
plt.tight_layout()
plt.show()
Another option would be to iterate through the generated "pathCollections" and assign a label (for some reason label= doesn't work in sns.pointplot).
fig, ax = plt.subplots()
sns.pointplot(x=x, y=1 + np.random.rand(10).cumsum(),
ax=ax, color='green')
sns.pointplot(x=x, y=2 + np.random.rand(10).cumsum(),
ax=ax, color='red')
sns.pointplot(x=x, y=3 + np.random.rand(10).cumsum(),
ax=ax, label='conf_int-', color='blue')
for curve, label in zip(ax.collections, ['factor', 'conf_int+', 'conf_int-']):
curve.set_label(label)
ax.set_title('Model M Discrete')
ax.legend(title='legend')
Still another way is to mimic a long form dataframe with hue which automatically creates a legend:
fig, ax = plt.subplots()
x = np.arange(10)
y1 = 1 + np.random.rand(10).cumsum()
y2 = 2 + np.random.rand(10).cumsum()
y3 = 3 + np.random.rand(10).cumsum()
sns.pointplot(x=np.tile(x, 3),
y=np.concatenate([y1, y2, y3]),
hue=np.repeat(['factor', 'conf_int+', 'conf_int-'], len(x)),
ax=ax, palette=['green', 'red', 'blue'])
Note that in both cases only a dot is shown in the legend, not a line.

Common y label on matplotlib not adjusting

I have two subplots and would like to have common x- and y-axes labels for both. My code is as follows:
fig, ax = plt.subplots()
ax = fig.add_subplot(111)
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
ax.set_ylabel("array2 stuff")
plt.subplot(2, 1, 1)
plt.plot(array1, array2, 'o-', label='stuff')
plt.title("my stuff")
plt.legend(loc="lower left")
plt.grid()
plt.subplot(2, 1, 2)
plt.plot(array1, array2, 'o-', label='stuff')
plt.xlabel("Date")
ax.set_ylabel("array2 stuff")
plt.legent(loc="lower left")
plt.ylim(-constant, constant)
plt.grid()
plot.show()
The x-axis label appears to work, but the y-label just won't center between the two plots. Instead it centers on the lower plot's y-axis.
Use text:
import matplotlib.pyplot as plt
import numpy as np
array1 = np.linspace(-10,10,10)
array2 = np.linspace(-10,10,10)
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
plt.subplot(2, 1, 1)
plt.plot(array1, array2, 'o-', label='stuff')
plt.title("my stuff")
plt.legend(loc="lower left")
plt.grid()
plt.subplot(2, 1, 2)
plt.plot(array1, array2, 'o-', label='stuff')
plt.xlabel("Date")
plt.legend(loc="lower left")
constant = 10
plt.ylim(-constant, constant)
plt.grid()
fig.text(.05, .5, 'array stuff', ha='center', va='center', rotation='vertical')
plt.show()

How to plot contourf colorbar in different subplot - matplotlib

This is a very similar question to "How to plot pcolor colorbar in a different subplot - matplotlib". I am trying to plot a filled contour plot and a line plot with a shared axis and the colorbar in a separate subplot (i.e. so it doesn't take up space for the contourf axis and thus muck up the x-axis sharing). However, the x-axis in my code does not rescale nicely:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
z = np.random.rand(20, 20)
x, y = np.arange(20), np.arange(20)
y2 = np.random.rand(20)
fig = plt.figure(figsize=(8, 8))
gs = mpl.gridspec.GridSpec(2, 2, height_ratios=[1, 2], width_ratios=[2, 1])
ax1 = fig.add_subplot(gs[1, 0])
ax2 = fig.add_subplot(gs[0, 0], sharex=ax1)
ax3 = fig.add_subplot(gs[1, 1])
cont = ax1.contourf(x, y, z, 20)
plt.tick_params(which='both', top=False, right=False)
ax2.plot(x, y2, color='g')
plt.tick_params(which='both', top=False, right=False)
cbar = plt.colorbar(cont, cax=ax3)
cbar.set_label('Intensity', rotation=270, labelpad=20)
plt.tight_layout()
plt.show()
which produces an x-axis scaled from 0 to 20 (inclusive) rather than 0 to 19, which means there is unsightly whitespace in the filled contour plot. Commenting out the sharex=ax1 in the above code means that the x-axis for the contour plot is scaled nicely, but not for the line plot above it and the plt.tick_params code has no effect on either axis.
Is there a way of solving this?
You could also turn off the autoscaling of x-axis for all subsequent call of plot on this axis so that it keeps the range set by contourf and sharex=True :
ax2.set_autoscalex_on(False)
This comes even before your call to ax2.plot() and I think it is better than calling ax2.set_xlim(0, 19) since you do not need to know what are the actual limit of your x-axis that may be needed.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
z = np.random.rand(20, 20)
x, y = np.arange(20), np.arange(20)
y2 = np.random.rand(20)
fig = plt.figure(figsize=(8, 8))
gs = mpl.gridspec.GridSpec(2, 1, height_ratios=[1, 2], width_ratios=[2])
ax1 = fig.add_subplot(gs[1, 0])
ax2 = fig.add_subplot(gs[0, 0], sharex=ax1)
cont = ax1.contourf(x, y, z, 20)
plt.tick_params(which='both', top=False, right=False)
ax2.set_autoscalex_on(False)
ax2.plot(x, y2, color='g')
axins = inset_axes(ax1,
width="5%", # width = 10% of parent_bbox width
height="100%", # height : 50%
loc=6,
bbox_to_anchor=(1.05, 0., 1, 1),
bbox_transform=ax1.transAxes,
borderpad=0,
)
cbar = plt.colorbar(cont, cax=axins)
plt.show()
You can use inset_axes for this without added another axis.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
z = np.random.rand(20, 20)
x, y = np.arange(20), np.arange(20)
y2 = np.random.rand(20)
fig = plt.figure(figsize=(8, 8))
gs = mpl.gridspec.GridSpec(2, 2, height_ratios=[1, 2], width_ratios=[2, 1])
ax1 = fig.add_subplot(gs[1, 0])
ax2 = fig.add_subplot(gs[0, 0], sharex=ax1)
cont = ax1.contourf(x, y, z, 20)
plt.tick_params(which='both', top=False, right=False)
ax2.plot(x, y2, color='g')
plt.tick_params(which='both', top=False, right=False)
axins = inset_axes(ax1,
width="5%", # width = 10% of parent_bbox width
height="100%", # height : 50%
loc=6,
bbox_to_anchor=(1.05, 0., 1, 1),
bbox_transform=ax1.transAxes,
borderpad=0,
)
cbar = plt.colorbar(cont, cax=axins)
plt.savefig('figure.jpg',bbox_inches='tight',dpi=200)

Average line for bar chart in matplotlib

How do we draw an average line (horizontal) for a histogram in using matplotlib?
Right now, I'm able to draw the histogram without any issues.
Here is the code I'm using:
## necessary variables
ind = np.arange(N) # the x locations for the groups
width = 0.2 # the width of the bars
plt.tick_params(axis='both', which='major', labelsize=30)
plt.tick_params(axis='both', which='minor', labelsize=30)
ax2 = ax.twinx()
## the bars
rects1 = ax.bar(ind, PAAE1, width,
color='0.2',
error_kw=dict(elinewidth=2,ecolor='red'),
label='PAAE1')
rects2 = ax.bar(ind+width, PAAE2, width,
color='0.3',
error_kw=dict(elinewidth=2,ecolor='black'),
label='PAAE2')
rects3 = ax2.bar(ind+width+width, AAE1, width,
color='0.4',
error_kw=dict(elinewidth=2,ecolor='red'),
label='AAE1')
rects4 = ax2.bar(ind+3*width, AAE2, width,
color='0.5',
error_kw=dict(elinewidth=2,ecolor='black'),
label='AAE3')
maxi = max(dataset[2])
maxi1 = max(dataset[4])
f_max = max(maxi, maxi1)
lns = [rects1,rects2,rects3,rects4]
labs = [l.get_label() for l in lns]
ax.legend(lns, labs, loc='upper center', ncol=4)
# axes and labels
ax.set_xlim(-width,len(ind)+width)
ax.set_ylim(0, 100)
ax.set_ylabel('PAAE', fontsize=25)
ax2.set_ylim(0, f_max+500)
ax2.set_ylabel('AAE (mW)', fontsize=25)
xTickMarks = dataset[0]
ax.set_xticks(ind+width)
xtickNames = ax.set_xticklabels(xTickMarks)
plt.setp(xtickNames, rotation=90, fontsize=25)
I want to plot the average line for PAAE 1, 2 and AAE 1, 2.
What should I be using to plot the average line?
If you'd like a vertical line to denote the mean use axvline(x_value). This will place a vertical line that always spans the full (or specified fraction of) y-axis. There's also axhline for horizontal lines.
In other works, you might have something like this:
ax.axvline(data1.mean(), color='blue', linewidth=2)
ax.axvline(data2.mean(), color='green', linewidth=2)
As a more complete, but unnecessarily complex example (most of this is nicely annotating the means with curved arrows):
import numpy as np
import matplotlib.pyplot as plt
data1 = np.random.normal(0, 1, 1000)
data2 = np.random.normal(-2, 1.5, 1000)
fig, ax = plt.subplots()
bins = np.linspace(-10, 5, 50)
ax.hist(data1, bins=bins, color='blue', label='Dataset 1',
alpha=0.5, histtype='stepfilled')
ax.hist(data2, bins=bins, color='green', label='Dataset 2',
alpha=0.5, histtype='stepfilled')
ax.axvline(data1.mean(), color='blue', linewidth=2)
ax.axvline(data2.mean(), color='green', linewidth=2)
# Add arrows annotating the means:
for dat, xoff in zip([data1, data2], [15, -15]):
x0 = dat.mean()
align = 'left' if xoff > 0 else 'right'
ax.annotate('Mean: {:0.2f}'.format(x0), xy=(x0, 1), xytext=(xoff, 15),
xycoords=('data', 'axes fraction'), textcoords='offset points',
horizontalalignment=align, verticalalignment='center',
arrowprops=dict(arrowstyle='-|>', fc='black', shrinkA=0, shrinkB=0,
connectionstyle='angle,angleA=0,angleB=90,rad=10'),
)
ax.legend(loc='upper left')
ax.margins(0.05)
plt.show()

Categories