bar x-tick not as same as the image - python

Im not sure if i use the wrong data or if there is and edit i need to do and not seeing it. It would be nice if someone could take a look at the code. The problem here is that yerr at the first bar is at x=0 and in the image the yerr is somewhere around 2.5
Does someone know what i did wrong or forgot to edit?
the end result should be:
my code:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1)
y_raw = np.random.randn(1000).cumsum() + 15
x_raw = np.linspace(0, 24, y_raw.size)
x_pos = x_raw.reshape(-1, 100).min(axis=1)
y_avg = y_raw.reshape(-1, 100).mean(axis=1)
y_err = y_raw.reshape(-1, 100).ptp(axis=1)
bar_width = x_pos[1] - x_pos[0]
x_pred = np.linspace(0, 30)
y_max_pred = y_avg[0] + y_err[0] + 2.3 * x_pred
y_min_pred = y_avg[0] - y_err[0] + 1.2 * x_pred
barcolor, linecolor, fillcolor = 'wheat', 'salmon', 'lightblue'
fig, axes = fig, ax = plt.subplots()
axes.set_title(label="Future Projection of Attitudes", fontsize=15)
plt.xlabel('Minutes since class began', fontsize=12)
plt.ylabel('Snarkiness (snark units)', fontsize=12)
fig.set_size_inches(8, 6, forward=True)
axes.fill_between(x_pred, y_min_pred, y_max_pred ,color='lightblue')
axes.plot(x_raw, y_raw, color='salmon')
vert_bars = axes.bar(x_pos, y_avg, yerr=y_err, color='wheat', width = bar_width, edgecolor='grey',error_kw=dict(lw=1, capsize=5, capthick=1, ecolor='gray'))
axes.set(xlim=[0, 30], ylim=[0,100])
plt.show()

yerr is meant to be the difference between the mean and the min/max. Now you're using the full difference between max and min. You might divide it by 2 to get a better approximation. To obtain the exact values, you could calculate them explicitly (see code example).
Further, by default, the bars are center aligned vs their x-position. You can use align='edge' to left-align them (as x_pos is calculated as the minimum of the range the bar represents). You could also set clip_on=False in the err_kw to make sure the error bars are never clipped by the axes.
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(1)
y_raw = np.random.randn(1000).cumsum() + 15
x_raw = np.linspace(0, 24, y_raw.size)
x_pos = x_raw.reshape(-1, 100).min(axis=1)
y_avg = y_raw.reshape(-1, 100).mean(axis=1)
y_min = y_raw.reshape(-1, 100).min(axis=1)
y_max = y_raw.reshape(-1, 100).max(axis=1)
bar_width = x_pos[1] - x_pos[0]
x_pred = np.linspace(0, 30)
y_max_pred = y_avg[0] + y_err[0] + 2.3 * x_pred
y_min_pred = y_avg[0] - y_err[0] + 1.2 * x_pred
barcolor, linecolor, fillcolor = 'wheat', 'salmon', 'lightblue'
fig, ax = plt.subplots(figsize=(8, 6))
ax.set_title(label="Future Projection of Attitudes", fontsize=15)
ax.set_xlabel('Minutes since class began', fontsize=12)
ax.set_ylabel('Snarkiness (snark units)', fontsize=12)
ax.fill_between(x_pred, y_min_pred, y_max_pred, color='lightblue')
ax.plot(x_raw, y_raw, color='salmon')
vert_bars = ax.bar(x_pos, y_avg, yerr=(y_avg - y_min, y_max - y_avg),
color='wheat', width=bar_width, edgecolor='grey', align='edge',
error_kw=dict(lw=1, capsize=5, capthick=1, ecolor='grey', clip_on=False))
ax.set(xlim=[0, 30], ylim=[0, 100])
plt.tight_layout()
plt.show()

Related

Matplotlib change colour of every second element in yaxis

So I have this plot here:
What I want to do is to have every second element of yaxis to be coloured for example in blue and the rest in red.
Here is the result I want to get:
and here is the code I got:
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
mpl.rcParams['toolbar'] = 'None'
plt.style.use('fivethirtyeight')
result_7_s = amount * s_7_days
result_14_s = amount * s_14_days
result_21_s = amount * s_21_days
result_7_fc = amount * fc_7_days
result_14_fc = amount * fc_14_days
result_21_fc = amount * fc_21_days
final_y = np.array([int(result_7_s), int(result_14_s),
int(result_21_s), int(result_7_fc),
int(result_14_fc), int(result_21_fc)])
fig, ax = plt.subplots(num = 'Test')
x = np.array([7, 14, 21])
plt.xticks(ticks = x, labels = x)
plt.yticks(ticks = final_y, labels = final_y)
plt.title(f'Prices for {amount} people')
plt.xlabel('Days')
plt.ylabel('Price')
plt.tight_layout()
ax.bar(x - 0.5, final_y[:3], width=1, color='#444444', label='Standard')
ax.bar(x + 0.5, final_y[3:], width=1, color='#e5ae38', label='First Class')
ax.tick_params(axis='y', colors = 'blue') # <-------
ax.yaxis.set_major_formatter('{x}$')
plt.legend()
plt.savefig('result.png')
plt.show()
Iterate over the tick labels to apply the desired color to each one of them:
for n, tick_label in enumerate(ax.yaxis.get_ticklabels()):
tick_label.set_color("red" if n%2 else "blue")
Here is the solution I came with:
for i in range(0, 3):
plt.gca().get_yticklabels()[i].set_color('blue')
for i in range(3, 6):
plt.gca().get_yticklabels()[i].set_color('red')

Map individual lines across two y axes in Matplotlib

I am trying to show cause and effect by displaying lines that are connected by two separate y axes.
eps_surprise = [56.15, 80.41, 218.48, 5.67, 2.99, 5.67]
stock_movement = [-5.72, 14.52, 18.78, -6.77, 6.03, -6.77]
fig, ax = plt.subplots()
y = list(zip(eps_surprise,stock_movement))
for i in y:
ax.plot((0,1),i)
plt.show()
As you can see in the above chart, I want to include a second y axis that would have a range limited to the min and max of stock_movement. However, my attempts in doing so do not result in the desired chart, as what is plotted is then based on the second axis alone, and not the first.
import matplotlib.pyplot as plt
eps_surprise = [56.15, 80.41, 218.48, 5.67, 2.99, 5.67]
stock_movement = [-5.72, 14.52, 18.78, -6.77, 6.03, -6.77]
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.set_ylim(min(eps_surprise),max(eps_surprise))
ax2.set_ylim(min(stock_movement),max(stock_movement))
y = list(zip(eps_surprise,stock_movement))
for i in y:
plt.plot((0,1),i)
plt.show()
The desired output would look something like as follows:
Not sure if this is what you are asking exactly, but given your question it's the best I can picture.
import matplotlib.pyplot as plt
eps_surprise = [56.15, 80.41, 218.48, 5.67, 2.99, 5.67]
stock_movement = [-5.72, 14.52, 18.78, -6.77, 6.03, -6.77]
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.set_ylim(min(eps_surprise),max(eps_surprise))
ax2.set_ylim(min(stock_movement),max(stock_movement))
# plot eps surprise and stock movement on the two separate axes
l1 = ax1.plot(eps_surprise, 'k--', label = 'eps surprise')
l2 = ax2.plot(stock_movement, 'r', label = 'stock movement')
# create legend for both axes
lns = [l1[0], l2[0]]
labs = [l.get_label() for l in lns]
ax2.legend(lns, labs)
ax1.set_ylabel('eps surprise')
ax2.set_ylabel('stock movement')
Honestly, though, if I were trying to show a relationship between two variables, I'd be more tempted to make a scatter plot or a regression.
from sklearn.linear_model import LinearRegression
regressor = LinearRegression()
regressor.fit([[i,] for i in eps_surprise],
[[i,] for i in stock_movement])
x = [[min(eps_surprise)], [max(eps_surprise)]]
plt.plot(eps_surprise, stock_movement, '.')
plt.plot(x, regressor.predict(x))
plt.grid()
plt.xlabel('eps surprise')
plt.ylabel('stock movement')
UPDATE
Based on the update in your question of how you want your original figure to look, here's how I would do it. The second set of axes are purely for labelling and instead I scaled the stock movement values to fit on your ax1 scale.
import matplotlib.pyplot as plt
def map_to_eps(stock_movement, eps_surprise):
ybounds = [min(stock_movement), max(stock_movement)]
dy = ybounds[1] - ybounds[0]
xbounds = [min(eps_surprise), max(eps_surprise)]
dx = xbounds[1] - xbounds[0]
return([(y - ybounds[0]) / dy * dx + xbounds[0] for y in stock_movement], dy, dx)
eps_surprise = [56.15, 80.41, 218.48, 5.67, 2.99, 5.67]
stock_movement = [-5.72, 14.52, 18.78, -6.77, 6.03, -6.77]
(stock_eps, dstock, deps) = map_to_eps(stock_movement, eps_surprise)
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.set_ylim(min(eps_surprise) - 0.05 * deps,max(eps_surprise) + 0.05 * deps)
ax2.set_ylim(min(stock_movement) - 0.05 * dstock ,max(stock_movement) + 0.05 * dstock)
y = list(zip(eps_surprise,stock_eps))
for i in y:
ax1.plot((0,1),i)
plt.xticks([])
ax1.set_ylabel('eps surprise')
ax2.set_ylabel('stock movement')

How to change background color of inset figure

I'm trying to create an inset figure that has a different projection from the parent. The only issue I have at this point is the inset figures's tick labels are not legible because they are black and blend in with the plot behind it. I could change the color of the ticks and labels to white, but that does not help when the data in ax0 yields lighter colors. Here is the MWE:
import calipsoFunctions as cf
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np
import pylab as pl
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
from mpl_toolkits.axes_grid1.inset_locator import inset_axes, mark_inset, InsetPosition
x, y = np.arange(100), np.arange(200)
X, Y = np.meshgrid(x, y)
C = np.random.randint(0, 100, (200, 100))
fig = pl.figure(figsize=(6.5, 5.25))
gs0 = pl.GridSpec(3, 1)
gs0.update(left=0.08, right=0.925,
top=0.95, bottom=0.33,
hspace=0.10, wspace=0.0)
gs1 = pl.GridSpec(1, 2)
gs1.update(left=0.08, right=0.925,
top=0.225, bottom=0.05,
hspace=0.0, wspace=0.025)
# create primary axes
ax0 = pl.subplot(gs0[0])
ax1 = pl.subplot(gs0[1])
ax0.pcolormesh(X, Y, C, vmin=0, vmax=75)
ax1.pcolormesh(X, Y, C, vmin=0, vmax=75)
# add map plot (inset axis)
loc_box = [0.8, 0.55, 0.20, 0.45]
ax0_inset = fig.add_axes(loc_box,
projection=ccrs.PlateCarree(),
aspect="auto",
facecolor="w",
frameon=True)
lat_array = np.arange(-20, 20)
lon_array = np.arange(-10, 10, 0.5)
ax0_inset.plot(lat_array, lon_array, "k-", lw=1)
ip = InsetPosition(ax0, loc_box)
ax0_inset.set_axes_locator(ip)
ax0_inset.coastlines(resolution="10m", linewidth=0.25, color="k")
ax0_inset.add_feature(cfeature.LAND)
llat, ulat = lat_array.min(), lat_array.max()
llon, ulon = lon_array.min(), lon_array.max()
llat = np.round(llat / 10) * 10
ulat = np.round(ulat / 10) * 10
llon = np.round(llon / 5) * 5
ulon = np.round(ulon / 5) * 5
ax0_inset.set_yticks(np.arange(llat, ulat, 20), minor=False)
ax0_inset.set_yticks(np.arange(llat, ulat, 10), minor=True)
ax0_inset.set_yticklabels(np.arange(llat, ulat, 20),
fontsize=8)
ax0_inset.yaxis.set_major_formatter(LatitudeFormatter())
ax0_inset.set_xticks(np.arange(llon, ulon, 5), minor=False)
ax0_inset.set_xticks(np.arange(llon, ulon, 1), minor=True)
ax0_inset.set_xticklabels(np.arange(llon, ulon, 5),
fontsize=8,
rotation=45)
ax0_inset.xaxis.set_major_formatter(LongitudeFormatter())
ax0_inset.grid()
ax0_inset.tick_params(which="both",
axis="both",
direction="in",
labelsize=8)
fig.show()
Is there a way to change the background color of ax0_inset so that these tick labels are legible? I tried changing the face_color to "w", but that did not work. Ideally, I want the same behavior as ax0.figure.set_facecolor("w"), but for the ax0_inset axis. Is this doable?
Following #Mr. T's comment suggestion, a work-around solution could be:
# insert transparent (or opaque) rectangle around inset_axes plot
# to make axes labels more visible
# make buffer variable to control amount of buffer around inset_axes
buffer = 0.1 # fractional axes coordinates
# use ax inset tuple coords in loc_box to add rectangle patch
# [left, bottom, width, height] (fractional axes coordinates)
fig.add_patch(plt.Rectangle((
loc_box[0]-buffer, loc_box[1]-buffer),
loc_box[2]+buffer, loc_box[3]+buffer,
linestyle="-", edgecolor="k", facecolor="w",
linewidth=1, alpha=0.75, zorder=5,
transform=ax0.transAxes))

Increase space between y tick and custom x axis

I'm trying to a build a plot that has an exponential function on the top and the utility function on the bottom. With the Y-Axis in the top plot showing the latency and X-Axis as the congestion; similarly, in the second plot, Y-Axis is the throughput and the X-Axis is the congestion.
Where I fail to get is, how do I set the X-Axis as a percentage, and is there a way to superimpose these two graphs.
#!/usr/bin/env python3
import numpy as np
import math
import matplotlib.mlab as mlab
import matplotlib.pyplot as plt
import matplotlib
fig = plt.figure()
x = np.arange(1,9,1)
y = [math.exp(_) for _ in x]
ax = fig.add_subplot(211)
ax.plot(x, y)
ax.set_ylabel('Y_plot1')
ax.set_xlabel('X_plot1')
ax.set_yticks([],[])
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.yaxis.set_tick_params(which='major', direction='out')
ax.set_ymargin(1)
ax1 = fig.add_subplot(212)
mu = 5
variance = 1
sigma = math.sqrt(variance)
x_normal = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
y_normal = mlab.normpdf(x_normal, mu, sigma)
#y_normal += 1000
x_normal = [0, 0] + list(x_normal)
y_normal = [0, 0] + list(y_normal)
ax1.plot(x_normal, y_normal)
ax1.set_ylabel('Y_plot2')
ax1.set_xlabel('X_plot2')
ax1.set_yticks([],[])
ax1.spines['right'].set_visible(False)
ax1.spines['top'].set_visible(False)
ax1.xaxis.set_ticks_position('bottom')
ax1.yaxis.set_ticks_position('left')
ax1.set_ymargin(1)
fig.tight_layout()
fig.savefig('bw-latency' +'.pdf',format='pdf',bbox_inches='tight', pad_inches=0.1, dpi=1000)
plt.clf()
plt.close()
To convert your x-axis to percent, you could normalize x_normaland adjust the xticks:
x_normal = x_normal/(max(x_normal)-min(x_normal)) + min(x_normal)
ax1.plot(x_normal, y_normal)
ax1.set_xticks(np.linspace(0,1,5))
ax1.set_xticklabels([str(int(i*100)) for i in np.linspace(0,1,5)])
To superimpose two graphs, have a look at: https://matplotlib.org/gallery/api/two_scales.html
I your case:
ax3 = ax1.twinx()
y = [math.exp(_) for _ in x_normal]
ax3.plot(x_normal, y,color="r")
EDIT: Is this the kind of output you are seeking?:
Here is the code that worked for me:
def plot_percentage(x, y, ax):
x = x/max(x)
ax.plot(x, y)
ax.set_xticks(np.linspace(0, 1, 10))
ax.set_xticklabels([str(int(i*100)) for i in np.linspace(0,1, 10)])
fig = plt.figure()
x = np.arange(1,9,1)
y = [math.exp(_) for _ in x]
ax = fig.add_subplot(211)
plot_percentage(x, y, ax)
ax.set_ylabel('Y_plot1')
ax.set_xlabel('X_plot1')
ax.set_yticks([],[])
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.yaxis.set_tick_params(which='major', direction='out')
ax.set_ymargin(1)
ax1 = fig.add_subplot(212)
mu = 5
variance = 1
sigma = math.sqrt(variance)
x_normal = np.linspace(mu - 3*sigma, mu + 3*sigma, 100)
y_normal = mlab.normpdf(x_normal, mu, sigma)
#y_normal += 1000
x_normal = [0, 0] + list(x_normal)
y_normal = [0, 0] + list(y_normal)
plot_percentage(x_normal, y_normal, ax1)
ax3 = ax1.twinx()
y = [math.exp(_) for _ in x_normal]
plot_percentage(x_normal, y, ax3)
plt.show()

How to show Cartesian system in polar plot in python?

Here I tried to add the polar plot on top of the Cartesian grid,but what I got instead was 2 separate figures(one polar another Cartesian),I want this polar figure to be embedded in the Cartesian plot. Also I have used some of the code previously available as I am new to matplotlib.
from pylab import *
import matplotlib.pyplot as plt
x = [0,10,-3,-10]
y = [0,10,1,-10]
color=['w','w','w','w']
fig = plt.figure()
ax1 = fig.add_subplot(111)
scatter(x,y, s=100 ,marker='.', c=color,edgecolor='w')
circle1=plt.Circle((0,0),5,color='r',fill=False)
circle_min=plt.Circle((0,0),4.5,color='g',fill=False)
circle_max=plt.Circle((0,0),5.445,color='b',fill=False)
fig = plt.gcf()
fig.gca().add_artist(circle1)
fig.gca().add_artist(circle_min)
fig.gca().add_artist(circle_max)
left,right = ax1.get_xlim()
low,high = ax1.get_ylim()
arrow( left, 0, right -left, 0, length_includes_head = True, head_width = 0.15 )
arrow( 0, low, 0, high-low, length_includes_head = True, head_width = 0.15 )
grid()
fig = plt.figure()
ax2 = fig.add_subplot(111)
scatter(x,y, s=100 ,marker='.', c=color,edgecolor='w')
circle2=plt.Circle((0,0),5,color='r',fill=False)
circle_min=plt.Circle((0,0),4.5,color='g',fill=False)
circle_max=plt.Circle((0,0),5.445,color='b',fill=False)
fig = plt.gcf()
fig.gca().add_artist(circle2)
fig.gca().add_artist(circle_min)
fig.gca().add_artist(circle_max)
left,right = ax2.get_xlim()
low,high = ax2.get_ylim()
arrow( left, 0, right -left, 0, length_includes_head = True, head_width = 0.15 )
arrow( 0, low, 0, high-low, length_includes_head = True, head_width = 0.15 )
import numpy as np
import matplotlib.pyplot as plt
theta = np.linspace(-np.pi, np.pi, 100)
r1 = 1 - np.sin(3*theta)
r2 = 1 + np.cos(theta)
ax = plt.subplot(111, polar=True, # add subplot in polar coordinates
axisbg='Azure') # background colour
ax.set_rmax(2.2) # r maximum value
ax.grid(True) # add the grid
ax.plot(theta, r1,
color='Tomato', # line colour
ls='--', # line style
lw=3, # line width
label='a 3-fold curve') # label
ax.plot(theta, r2,
color='purple',
linewidth=3,
ls = '-',
label = 'a cardioid')
ax.legend(loc="lower right") # legend location
titlefont = {
'family' : 'serif',
'color' : 'black',
'weight' : 'bold',
'size' : 16,
}
ax.set_title("A plot in polar coordinates", # title
va='bottom', # some space below the title
fontdict = titlefont # set the font properties
)
grid()
show()
#I am getting a separate Cartesian image + a polar image while what I need is both the things in a single image
import matplotlib.pyplot as plt
import numpy as np
#########################################
color=['w','w','w','w']
theta = np.linspace(-np.pi, np.pi, 100)
fig = plt.figure()# initializing the figure
rect = [0.1, 0.1, 0.8, 0.8]# setting the axis limits in [left, bottom, width, height]
ax_carthesian = fig.add_axes(rect)# the carthesian axis:
ax_polar = fig.add_axes(rect, polar=True, frameon=False)# the polar axis:
#########################################
ax_carthesian.add_artist(plt.Circle((0.5,0.5),5/15,color='r',fill=False))
ax_carthesian.add_artist(plt.Circle((0.5,0.5),4.5/15,color='g',fill=False))
ax_carthesian.add_artist(plt.Circle((0.5,0.5),5.445/15,color='b',fill=False))
ax_polar.plot(theta, 1 - np.sin(3*theta), color='Tomato',ls='--',lw=1, label='a 3-fold curve')
ax_polar.plot(theta, 1 + np.cos(theta), color='purple',linewidth=1,ls = '-',label = 'a cardioid')
plt.show()
I am not used to matplotlib but I reduced your code to his minimum to better understand it and make it look less redudant. look at what I get:
import pylab
import matplotlib.pyplot as plt
import numpy as np
#########################################
x = [0,10,-3,-10]
y = [0,10,1,-10]
color=['w','w','w','w']
theta = np.linspace(-np.pi, np.pi, 100)
#########################################
pylab.scatter(x,y, s=100 ,marker='.', c=color,edgecolor='w')
plt.gcf().gca().add_artist(plt.Circle((0,0),5,color='r',fill=False))
plt.gcf().gca().add_artist(plt.Circle((0,0),4.5,color='g',fill=False))
plt.gcf().gca().add_artist(plt.Circle((0,0),5.445,color='b',fill=False))
plt.figure().add_subplot(111)
ax = plt.subplot(111, polar=True,axisbg='Azure')
ax.plot(theta, 1 - np.sin(3*theta),color='Tomato',ls='--',lw=3,label='a 3-fold curve')
ax.plot(theta, 1 + np.cos(theta),color='purple',linewidth=3,ls = '-',label = 'a cardioid')
pylab.show()
it is nearly the same result...

Categories