How to remove a particular grid line? - python

please see the result graph image below.
I wish to remove only one major grid line at y-axis value of 10 (Blue horizontal line), and keep all other grid lines.
Is there a way to do that?
plt.rcParams['font.family'] = 'Arial'
fig, ax = plt.subplots(figsize=(14.78, 9.84))
plt.xlim(0, 105)
plt.ylim(0, 10)
ax.xaxis.set_minor_locator(AutoMinorLocator(2))
ax.yaxis.set_minor_locator(AutoMinorLocator(2))
ax.spines['bottom'].set_linewidth(1.5)
ax.spines['left'].set_linewidth(1.5)
ax.spines['top'].set_linewidth(0)
ax.spines['right'].set_linewidth(0)
# Grid setting
plt.grid(True, color='#0100FF', which="major", ls="-")
plt.grid(True, color='#0BC904', which="minor", ls="-")
plt.xlabel("Indicator Amplitude, %FSH", fontsize=28, labelpad=15)
plt.ylabel("Function Generator Output, V", fontsize=28, labelpad=15)
# Axis setting
plt.tick_params(which="major", labelsize=22, length=10, pad=10, width=1.5)
plt.tick_params(which="minor", length=8, width=1.5)
# Plot scatter & line
plt.plot(FSH_axis, x_value[2:], color='black', marker='^', linewidth=1.5, markersize=8, label="40 dB")
plt.plot(FSH_axis, y_value[2:], color='red', marker='o', linewidth=1.5, markersize=8, label="60 dB")
plt.plot(FSH_axis, z_value[2:], color='blue', marker='v', linewidth=1.5, markersize=8, label="80 dB")
plt.legend(loc=(1 / 16, 58 / 90), ncol=1, fontsize=20, frameon=True, framealpha=1, edgecolor="black")
plt.show()

We can catch all gridlines with get_ygridlines(), then access individual gridlines as Line2D objects to modify them:
from matplotlib import pyplot as plt
from matplotlib.ticker import AutoMinorLocator
plt.rcParams['font.family'] = 'Arial'
fig, ax = plt.subplots(figsize=(14.78, 9.84))
plt.xlim(0, 105)
plt.ylim(0, 10)
ax.xaxis.set_minor_locator(AutoMinorLocator(2))
ax.yaxis.set_minor_locator(AutoMinorLocator(2))
ax.spines['bottom'].set_linewidth(1.5)
ax.spines['left'].set_linewidth(1.5)
ax.spines['top'].set_linewidth(0)
ax.spines['right'].set_linewidth(0)
# Grid setting
plt.grid(True, color='#0100FF', which="major", ls="-")
plt.grid(True, color='#0BC904', which="minor", ls="-")
#this part is added
#set the last horizontal gridline invisible
ygridlines = ax.get_ygridlines()
gridline_of_interest = ygridlines[-1]
gridline_of_interest.set_visible(False)
plt.xlabel("Indicator Amplitude, %FSH", fontsize=28, labelpad=15)
plt.ylabel("Function Generator Output, V", fontsize=28, labelpad=15)
# Axis setting
plt.tick_params(which="major", labelsize=22, length=10, pad=10, width=1.5)
plt.tick_params(which="minor", length=8, width=1.5)
# Plot scatter & line
FSH_axis = [10, 40, 100]
plt.plot(FSH_axis, [1, 3, 2], color='black', marker='^', linewidth=1.5, markersize=8, label="40 dB")
plt.plot(FSH_axis, [2, 2, 3], color='red', marker='o', linewidth=1.5, markersize=8, label="60 dB")
plt.plot(FSH_axis, [2, 1, 1], color='blue', marker='v', linewidth=1.5, markersize=8, label="80 dB")
plt.legend(loc=(1 / 16, 58 / 90), ncol=1, fontsize=20, frameon=True, framealpha=1, edgecolor="black")
plt.show()
Sample output:
Of course, the corresponding get_xgridlines() also exists.

Related

Putting two plots with different axes into one with Matplotlib

I have two plots in Matplotlib that I would like to merge. They have different axes and scales. Here is the code for each of them.
Electrical Power Plot:
#Case Study: Curtailment
from matplotlib import pyplot as plt
%matplotlib inline
load = [0, 250, 250, 250, 250, 250, 665, 2500, 2500, 2500, 2500, 2500,0,2500, 2366, 250, 250, 373, 2500,0, 2500, 0, 2500,250, 0]
hours = list(range(25)) # [0, 1, 2, ... 22, 23, 24]
labels = [f'{h:02d}:00' for h in hours] # ["00:00", "01:00", ... "23:00", "24:00"]
fig = plt.figure(linewidth=1, figsize=(9, 5))
ax = plt.gca()
ax.plot(hours, load, color="goldenrod",drawstyle="steps-post", linewidth=3) # <- drawstyle argument.
ax.set_xlabel("Time of day", fontsize=14, labelpad=8)
ax.set_ylabel("Electrical power in W", fontsize=14, labelpad=8)
ax.set_xlim(0, 24)
ax.set_ylim(0, 3000)
plt.xticks(hours, labels=labels, rotation=90)
plt.grid(axis='y', alpha=.4)
ax.tick_params(axis='both', which='major', labelsize=14)
# (Optional) ax.legend(loc='center left', bbox_to_anchor=(0.03, 1.15), fontsize = 14, ncol=3)
plt.tight_layout() # This must be called last, after all elements (plot and legend) are ready.
plt.savefig('CS_Curtailment_ElectricalLoad.png', edgecolor='black', dpi=400, bbox_inches='tight')
plt.show()
Temperature Plot:
#Case Study: Curtailment
from matplotlib import pyplot as plt
%matplotlib inline
temperature = [
21.00,
21.02,
20.96,
20.85,
20.68,
20.46,
20.40,
20.56,
20.77,
21.06,
21.41,
21.79,
21.10,
21.57,
22.00,
21.47,
20.92,
20.46,
20.92,
20.31,
20.77,
20.35,
20.90,
21.00,
21.00
]
hours = list(range(25)) # [0, 1, 2, ... 22, 23, 24]
labels = [f'{h:02d}:00' for h in hours] # ["00:00", "01:00", ... "23:00", "24:00"]
fig = plt.figure(linewidth=1, figsize=(9, 5))
ax = plt.gca()
ax.plot(hours, temperature, color="red", linewidth=3) # <- drawstyle argument.
ax.set_xlabel("Time of day", fontsize=14, labelpad=8)
ax.set_ylabel("Temperature in °C", fontsize=14, labelpad=8)
ax.set_xlim(0, 24)
ax.set_ylim(20, 22.5)
plt.xticks(hours, labels=labels, rotation=90)
plt.grid(axis='y', alpha=.4)
ax.tick_params(axis='both', which='major', labelsize=14)
# (Optional) ax.legend(loc='center left', bbox_to_anchor=(0.03, 1.15), fontsize = 14, ncol=3)
plt.tight_layout() # This must be called last, after all elements (plot and legend) are ready.
plt.savefig('CS_Curtailment_Temperature.png', edgecolor='black', dpi=400, bbox_inches='tight')
plt.show()
I would like to have the electrical power axis on the left (first plot) and the temperature axis on the right (second plot). Of course the two plots have similar x-axis values.
Can you do this with Matplotlib?
I'd appreciate every comment.
Yes this can be done in matplotlib to do so, first generate the first ax (electrical power) and then instantiate the second axes
ax.plot(hours, load, color="goldenrod",drawstyle="steps-post", linewidth=3)
# ...
#generate the second instance
ax2 = ax.twinx()
ax2.plot(hours, temperature, color="red", linewidth=3)
# ... set additional configuration for ax2
Both axes will share the same x-axes and the same fig, so make sure that before showing the plot to tight the layout, otherwise y-label might be clipped.
fig.tight_layout()
plt.show()
EDIT:
To handle both axes at the same time, you need to use the figure object, so use it to save them to a png and set the legend. legend() method need to receive the labels which you can set manually of on each ax.plot( ..., label='<label>')
get the current figure before plt.show()
Set the legend using the figure object.
Save the image using the figure object.
Show the image.
The code:
fig = plt.gcf()
fig.legend(loc='center left', bbox_to_anchor=(0.15, 1.07), fontsize=14, ncol=3)
fig.savefig('CS_Curtailment_CombinedDiagram.png',
edgecolor='black', dpi=400, bbox_inches='tight')
plt.show()

For scatterplot with matplotlib how to include in the legend gradient for dot size and colour?

I create two scatterplots with matplotlib in python with this code, the data for the code is here:
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize
fig = plt.figure(figsize=(20,12))
ax1 = fig.add_subplot(111)
ax3 = ax1.twinx()
norm = Normalize(vmin=0.95*min(arr), vmax=1.05*max(arr))
ax1.scatter(x, y1, s=20, c=arr, cmap='Blues_r', norm=norm, marker='x', label='bla1')
ax3.scatter(x, y2, s=(20*(1.1-arr))**3.5, c=arr, cmap='Reds_r', norm=norm, marker='^', label='bla1')
The created fig. looks like this:
So, the dot size (in ax3) and the dot colour (in ax1 and ax3) are taken from arrays containing floats with all kinds of values in the range [0,1]. My question: How do I create a legend that displays the corresponding y-values for, let's say 5 different dot sizes and 5 different colour nuances?
I would like the legend to look like in the figure below (source here), but with the colour bar and size bar put into a single legend, if possible. Thanks for suggestions and code!
# using your data in dataframe df
# create s2
df['s2'] = (20*(1.1-df.arr))**3.5
fig = plt.figure(figsize=(20,12))
ax1 = fig.add_subplot(111)
ax3 = ax1.twinx()
norm = Normalize(vmin=0.95*min(df.arr), vmax=1.05*max(df.arr))
p1 = ax1.scatter(df.x, df.y1, s=20, c=df.arr, cmap='Blues_r', norm=norm, marker='x')
fig.colorbar(p1, label='arr')
p2 = ax3.scatter(df.x, df.y2, s=df.s2, c=df.arr, cmap='Reds_r', norm=norm, marker='^')
fig.colorbar(p2, label='arr')
# create the size legend for red
for x in [15, 80, 150]:
plt.scatter([], [], c='r', alpha=1, s=x, label=str(x), marker='^')
plt.legend(loc='upper center', bbox_to_anchor=(1.23, 1), ncol=1, fancybox=True, shadow=True, title='s2')
plt.show()
There's no legend for p1 because the size is static.
I think this would be better as two separate plots
I used Customizing Plot Legends: Legend for Size of Points
Separate
fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(20, 10))
norm = Normalize(vmin=0.95*min(df.arr), vmax=1.05*max(df.arr))
p1 = ax1.scatter(df.x, df.y1, s=20, c=df.arr, cmap='Blues_r', norm=norm, marker='x')
fig.colorbar(p1, ax=ax1, label='arr')
p2 = ax2.scatter(df.x, df.y2, s=df.s2, c=df.arr, cmap='Reds_r', norm=norm, marker='^')
fig.colorbar(p2, ax=ax2, label='arr')
# create the size legend for red
for x in [15, 80, 150]:
plt.scatter([], [], c='r', alpha=1, s=x, label=str(x), marker='^')
plt.legend(loc='upper center', bbox_to_anchor=(1.2, 1), ncol=1, fancybox=True, shadow=True, title='s2')
plt.show()

How to create a visualization for events along a timeline?

I'm building a visualization with Python.
There I'd like to visualize fuel stops and the fuel costs of my car. Furthermore, car washes and their costs should be visualized as well as repairs. The fuel costs and laundry costs should have a higher bar depending on the costs. I created the visualization below to describe the concepts.
How to create such a visualization with matplotlib?
This is the visualization being built:
Yes, this kind of visualization is perfectly possible with matplotlib. To store the data, numpy arrays are usually very handy.
Here is some code to get you started:
import matplotlib.pyplot as plt
import numpy as np
refuel_km = np.array([0, 505.4, 1070, 1690])
refuel_cost = np.array([40.1, 50, 63, 55])
carwash_km = np.array([302.0, 605.4, 901, 1331, 1788.2])
carwash_cost = np.array([35.0, 40.0, 35.0, 35.0, 35.0])
repair_km = np.array([788.0, 1605.4])
repair_cost = np.array([135.0, 74.5])
fig, ax = plt.subplots(figsize=(12,3))
plt.scatter(refuel_km, np.full_like(refuel_km, 0), marker='o', s=100, color='lime', edgecolors='black', zorder=3, label='refuel')
plt.bar(refuel_km, refuel_cost, bottom=15, color='lime', ec='black', width=20, label='refuel cost')
plt.scatter(carwash_km, np.full_like(carwash_km, 0), marker='d', s=100, color='tomato', edgecolors='black', zorder=3, label='car wash')
plt.bar(carwash_km, -carwash_cost, bottom=-15, color='tomato', ec='black', width=20, label='car wash cost')
plt.scatter(repair_km, np.full_like(repair_km, 0), marker='^', s=100, color='lightblue', edgecolors='black', zorder=3, label='car repair')
#plt.bar(repair_km, -repair_cost, bottom=-15, color='lightblue', ec='black', width=20)
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['left'].set_color('none')
ax.tick_params(axis='x', length=20)
ax.set_yticks([]) # turn off the yticks
_, xmax = ax.get_xlim()
ymin, ymax = ax.get_ylim()
ax.set_xlim(-15, xmax)
ax.set_ylim(ymin, ymax+25) # make room for the legend
ax.text(xmax, -5, "km", ha='right', va='top', size=14)
plt.legend(ncol=5, loc='upper left')
plt.tight_layout()
plt.show()

Plot a vertical Normal Distribution in Python

This is my current code of my plotting with matplotlib:
from matplotlib import pyplot
import numpy as np
std=1.5
al=0.6
dpi=80
target=38.9675
mc_min=np.array([10-std, 15-std, 20-std, 25-std, 30-std, 35-std])
mc_max=np.array([2*std, 2*std, 2*std, 2*std, 2*std, 2*std])
mc_min_out=np.array([40-std, 45-std])
mc_max_out=np.array([2*std, 2*std])
x = np.linspace(10, 35, 6)
x_out=np.linspace(40, 45, 2)
a=35+((target-35)*1.5)
b=((target-35)*1.5)
#8,6
pyplot.figure(num=None, figsize=(8, 6), dpi=dpi, facecolor='w', edgecolor='k')
pyplot.bar(x, mc_min, width=3, color ='#000000', align='center', alpha=1)
pyplot.bar(x_out, mc_min_out, width=3, color ='#000000', align='center', alpha=al/2)
pyplot.bar(x, mc_max, width=3, bottom=mc_min, color ='#ff0000', align='center', alpha=al)
pyplot.bar(x_out, mc_max_out, width=3, bottom=mc_min_out, color ='#ff0000', align='center', alpha=al/2)
pyplot.scatter(35, target, s=20, c='y')
pyplot.scatter(35, a, s=20, c='b')
pyplot.scatter(30, a-5, s=20, c='b')
pyplot.scatter(25, a-10, s=20, c='b')
pyplot.scatter(20, a-15, s=20, c='b')
pyplot.scatter(15, a-20, s=20, c='b')
pyplot.scatter(10, a-25, s=20, c='b')
pyplot.axvline(x=35, ymin=0, ymax = 0.9, linewidth=1, color='k')
pyplot.axvline(x=30, ymin=0, ymax = 0.9, linewidth=1, color='k')
pyplot.axvline(x=25, ymin=0, ymax = 45, linewidth=1, color='k')
pyplot.axvline(x=20, ymin=0, ymax = 45, linewidth=1, color='k')
pyplot.axvline(x=15, ymin=0, ymax = 45, linewidth=1, color='k')
pyplot.axvline(x=10, ymin=0, ymax = 45, linewidth=1, color='k')
pyplot.axhline(y=10, xmin=0.04, xmax=0.12, linewidth=1, color='k')
pyplot.axhline(y=15, xmin=0.16, xmax=0.242, linewidth=1, color='k')
pyplot.axhline(y=20, xmin=0.278, xmax=0.36, linewidth=1, color='k')
pyplot.axhline(y=25, xmin=0.4, xmax=0.48, linewidth=1, color='k')
pyplot.axhline(y=30, xmin=0.515, xmax=0.6, linewidth=1, color='k')
pyplot.axhline(y=35, xmin=0.64, xmax=0.72, linewidth=1, color='k')
pyplot.axhline(y=target, xmin=0.67, xmax=0.69, linewidth=1, color='k')
pyplot.axhline(y=(a+b), xmin=0.66, xmax=0.70, linewidth=1, color='k')
pyplot.axhline(y=(a-5+b), xmin=0.54, xmax=0.58, linewidth=1, color='k')
pyplot.axhline(y=(a-10+b), xmin=0.42, xmax=0.46, linewidth=1, color='k')
pyplot.axhline(y=(a-15+b), xmin=0.3, xmax=0.34, linewidth=1, color='k')
pyplot.axhline(y=(a-20+b), xmin=0.18, xmax=0.22, linewidth=1, color='k')
pyplot.axhline(y=(a-25+b), xmin=0.06, xmax=0.10, linewidth=1, color='k')
pyplot.yticks(np.arange(0, 56, 5))
And this is the result:
My problem is that I want to plot a normal distribution in the vertical line that crosses the 35 x-positioned bar. The normal distribution would have a mean equal to the variable "a" and a standard deviation of value "b" and will fit between the edge of the red bar (35 x-positioned) and the top horizontal line that crosses the vertical 35 x-positioned line. The result would be as the second photo.
You can plot a Gaussian function in the position you want by adding x- and y-offsets to the plotted data. Here's an example function:
def draw_gaussian_at(support, sd=1.0, height=1.0,
xpos=0.0, ypos=0.0, ax=None, **kwargs):
if ax is None:
ax = plt.gca()
gaussian = np.exp((-support ** 2.0) / (2 * sd ** 2.0))
gaussian /= gaussian.max()
gaussian *= height
return ax.plot(gaussian + xpos, support + ypos, **kwargs)
xpos and ypos direct the center of the curve to that location, and sd and height control the shape of the curve. Use a negative value for height to have the curve "face" to the left. The support parameter is the range of y-values over which the curve runs, so in your case it would be something like np.linspace(a - 3.0 * b, a + 3.0 * b, 1000), which would plot the curve over 3 standard deviations centered at a.
Here's an example of the function's usage:
support = np.linspace(-2, 2, 1000)
fig, ax = plt.subplots()
for each in np.linspace(-2, 2, 5):
draw_gaussian_at(support, sd=0.5, height=-0.5, xpos=each, ypos=each, ax=ax, color='k')

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