Set steps on y-axis with matplotlib - python

Currently I have the problem that I do not get the steps on the y-axis (score) changed. My representation currently looks like this:
However, since only whole numbers are possible in my evaluation, these 0.5 steps are rather meaningless in my representation. I would like to change these steps from 0.5 to 1.0. So that I get the steps [0, 1, 2, 3, ...] instead of [0.0, 0.5, 1.0, 1.5, 2.0, ...].
My code broken down to the most necessary and simplified looks like this:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# some calculations
x = np.arange(len(something)) # the label locations
width = 0.35 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(x - width/2, test1_means, width, label='Test 1')
rects2 = ax.bar(x + width/2, test2_means, width, label='Test 2')
# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_ylabel('Scores')
ax.set_title('Something to check')
ax.set_xticks(x, something)
ax.legend()
ax.bar_label(rects1, padding=3)
ax.bar_label(rects2, padding=3)
fig.tight_layout()
plt.show()
In addition, after research, I tried setting the variable ax.set_yticks or adjusting the fig. Unfortunately, these attempts did not work.
What am I doing wrong or is this a default setting of matplotlib at this point?
Edit after comment:
My calculations are prepared on the basis of Excel data. Here is a reproducible code snippet with the current values how the code might look like in the final effect:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
stories = ["A", "B", "C", "D", "E"]
test1_means = [2, 3, 2, 3, 1]
test2_means = [0, 1, 0, 0, 0]
x = np.arange(len(stories)) # the label locations
width = 0.35 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(x - width/2, test1_means, width, label='Test 1')
rects2 = ax.bar(x + width/2, test2_means, width, label='Test 2')
# Add some text for labels, title and custom x-axis tick labels, etc.
ax.set_ylabel('Scores')
ax.set_title('Something')
ax.set_xticks(x, stories)
ax.legend()
ax.bar_label(rects1, padding=3)
ax.bar_label(rects2, padding=3)
fig.tight_layout()
plt.show()

You're looking for Axes.set_yticks. Add those lines right before the plot :
N = 1 # <- you can adjust the step here
ax.set_yticks(np.arange(0, max(test1_means + test2_means) + 1, N))
Output :

Based on this answer, you just need to do:
from matplotlib.ticker import MaxNLocator
# set y-axis to only show integer values
ax.yaxis.set_major_locator(MaxNLocator(integer=True))

Related

How to get rid of exponential value in python matplotlib bar graph? Instead of exponential values I want 0.1, 1, 10,100 and 1000

I am plotting bar graph using python matplotlib as shown in figure below. I am trying to get rid of exponential values on y axis but couldn't get rid of it.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter
# set width of bar
barWidth = 0.25
fig = plt.subplots(figsize =(12, 8))
params = {'legend.fontsize': 20,
'legend.handlelength': 2}
plt.rc('xtick', labelsize=20)
plt.rc('ytick', labelsize=20)
plt.rc('axes.formatter',useoffset=False)
plt.ticklabel_format(style='plain', axis='y', scilimits=(0,0))
plt.ticklabel_format(useOffset=False, style='plain')
# set height of bar
dpkt_val = [0.06, 0.33,0.58,3.02, 7.01]
scapy_val = [0.59, 2.41,5.85,24,56.15]
pyshark_val = [26.26,152.94, 261.14,1456.02,0] #
# Set position of bar on X axis
br1 = np.arange(len(dpkt_val))
br2 = [x + barWidth for x in br1]
br3 = [x + barWidth for x in br2]
plt.rcParams.update(params)
# Make the plot
plt.bar(br1, dpkt_val, color ='r', width = barWidth,
edgecolor ='grey', label ='dpkt',hatch='*')
plt.bar(br2, scapy_val, color ='g', width = barWidth,
edgecolor ='grey', label ='Scapy',hatch='//')
plt.bar(br3, pyshark_val, color ='b', width = barWidth,
edgecolor ='grey', label ='pyshark',hatch='-')
plt.ticklabel_format(useOffset=False, style='plain')
# Adding Xticks
plt.xlabel('Filesize', fontweight ='bold', fontsize = 20)
plt.ylabel('Time(sec)', fontweight ='bold', fontsize = 20)
plt.xticks([r + barWidth for r in range(len(dpkt_val))],
['100MB', '500MB', '1GB', '5GB', '10GB'],fontsize = 20)
plt.yticks(style='normal',fontsize=20)
plt.legend()
plt.yscale('log')
plt.show()
[![enter image description here][1]][1]
Instead of exponential values, I want 0.1, 1, 10,100, and 1000.
Any help is appreciated.
[1]: https://i.stack.imgur.com/wweIB.png
After you set log scale, that is, in your code, just before the last line, show
from matplotlib.ticker import FormatStrFormatter
# (...)
ax=plt.gca()
ax.yaxis.set_major_formatter(ScalarFormatter())
(gca get the default axes your are plotting ont. And the next line choose a scalar formatter for labels of y axis)

How to split the background/facecolor in parts?

I wanna have something similar to the following figures
How to archive such split?
I tried to set the face color but i cannt there only set a margin for x/y values. My x axis are in date format.
I just want something like the 1/4 green, 1/4 red and the other 2/4 default/no facecolor.
Then in the next plot 2/4 green, 1/4 red, 1/4 default and so on.
but also like the right plot. I also tried axvspan but it seems i have to set some values span and not a % part of the plot to be filled.
Any suggestions?
To split the x-range into 4 equal parts, the axes transform can be used. As axvspan doesn't seem to take the transform into account, explicit rectangles can be created:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
x = pd.date_range('20200101', periods=50, freq='D')
fig, axs = plt.subplots(nrows=3, ncols=2, figsize=(15, 4))
for i, ax_row in enumerate(axs):
for ax in ax_row:
ax.set_facecolor('lightblue')
ax.plot(x, np.random.randn(len(x)).cumsum(), color='navy')
ax.margins(x=0) # optionally remove the padding left and right
ax.add_patch(plt.Rectangle((i / 4, 0), 0.25, 1, transform=ax.transAxes, color='lime', alpha=0.3))
ax.add_patch(plt.Rectangle(((i + 1) / 4, 0), 0.25, 1, transform=ax.transAxes, color='crimson', alpha=0.3))
fig.set_facecolor('lightblue')
plt.tight_layout()
plt.show()

Title, tick, axis labels, nothing is showing in matplotlib

This is my code:
import numpy as np
import matplotlib.pyplot as plt
def plot_graph():
fig = plt.figure()
data = [[top3_empsearch, top5_empsearch, top7_empsearch], [top3_elastic, top5_elastic, top7_elastic]]
X = np.arange(3)
ax = fig.add_axes([0, 0, 1, 1])
ax.bar(X + 0.00, data[0], color='b', width=0.25)
ax.bar(X + 0.25, data[1], color='g', width=0.25)
ax.set_ylabel('Accuracy (in %)')
plt.title('Percentage accuracy for selected result in Top-3, Top-5, Top-7 in employee search vs elastic search')
plt.yticks(np.arange(0, 101, 10))
colors = {'empsearch':'blue', 'elastic':'green'}
labels = list(colors.keys())
handles = [plt.Rectangle((0,0),1,1, color=colors[label]) for label in labels]
plt.legend(handles, labels)
plt.style.use('dark_background')
plt.show()
plot_graph()
The outcome of this code is ->
No ticks, no labels, no title nothing is visible and I'm bamboozled. Will appreciate the help.
The only problem is in this line:
ax = fig.add_axes([0, 0, 1, 1])
Looking to the bibliography (https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.figure.Figure.html), you will see that the first parameter of add_axes() function is "rect", which refers to the the dimensions [left, bottom, width, height] of the new axes, all quantitie in fractions of figure width and height. So in your code you are giving exactly the dimensions of the figure, so the title, ticks, labels... are there but hidden. So you have to leave some space, reducing a bit the plot's dimensions. You could do it just by modifying:
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
Alternatively, you could replace that line by:
ax = fig.add_subplot(1,1,1)
and the result should be the same.
Here is my result:

How to add one custom tickline in matplotlib axes

Is there a programmatic way to force the appearance of a single tickline at the additional tick location shown below?
Requirements:
Tickline should be pointing down from x-axis
Tickline should extend to label 103 regardless of padding
Tickline should be the same color and thickness of axes
No changes to other ticks (ticklines or tick labels)
Code and sample image:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
fig, ax = plt.subplots(figsize=(6, 8 / 3))
fig.tight_layout()
x_limit = 103
x = [0, 10, 50, 100, x_limit]
y = [6, 2, 5, 2, 20]
ax.plot(x, y)
# Add a tick which represents the maximum x-value
xticks = ax.xaxis.get_majorticklocs()
ax.xaxis.set_ticks(np.append(xticks, x_limit))
# Change padding of tick in the event other ticks get too close
tick = ax.get_xaxis().get_major_ticks()[-1]
tick.set_pad(14)
tick.label1 = tick._get_text1()
# Set tight axes bounds around data
ax.set_ylim(0, max(y) + 1)
ax.set_xlim(0, x_limit)
EDIT: Tried tcaswell's solution and ended up with an annotation in the right place. I do notice some aliasing as if it doesn't look like an extension of the y-axis. Any ideas on how to clean this up?
You can do this with annotate and a bit of transform magic.
import matplotlib.transforms as mtransforms
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(9, 3), tight_layout=True)
ax.set_xlim(90, 105)
trans = mtransforms.blended_transform_factory(ax.transData, ax.transAxes)
tt = ax.annotate('103', (103, 0), xytext=(0, -12), transform=trans,
arrowprops={'arrowstyle': '-'}, ha='center', va='top',
textcoords='offset points')

Customizing legend in matplotlib

i'm plotting rectangles that have different colors in matplotlib. i would like each type of rectangle to have a single label that appears once in the legend. my code is:
import matplotlib.patches as patches
fig1 = plt.figure()
ax = plt.subplot(1,1,1)
times = [0, 1, 2, 3, 4]
for t in times:
if t % 2 == 0:
color="blue"
else:
color="green"
ax.add_patch(patches.Rectangle((t, 0.5), 0.1, 0.1,
facecolor=color,
label=color))
plt.xlim(times[0], times[-1] + 0.1)
plt.legend()
plt.show()
the problem is that each rectangle appears multiple in the legend. i would like to only have two entries in the legend: a blue rectangle labeled "blue", and a green rectangle labeled "green". how can this be achieved?
As documented here, you can control the legend by specifying the handles to the graphical objects for which you want the legends. In this case, two out of the five objects are needed, so you can store them in a dictionary
import matplotlib.pyplot as plt
import matplotlib.patches as patches
fig1 = plt.figure()
ax = plt.subplot(1,1,1)
times = [0, 1, 2, 3, 4]
handle = {}
for t in times:
if t % 2 == 0:
color="blue"
else:
color="green"
handle[color] = ax.add_patch(patches.Rectangle((t, 0.5), 0.1, 0.1,
facecolor=color,
label=color))
plt.xlim(times[0], times[-1] + 0.1)
print handle
plt.legend([handle['blue'],handle['green']],['MyBlue','MyGreen'])
plt.show()

Categories

Resources