I am using Matplotlib to plot a bar graph. Most of my data values are in the range of -10 to +30. However, I have two data values that are around -300.
When I plot my data, the -300 data value bar looks too big, and it hides the insights of the other bars. Is there a way that I can plot all bars in -10 to +30 range, clip the -300 bar at -30 and instead write a label "-300"?
use ax.set_ylim() to set the ylimits, and ax.annotate to write the label (and, if you like, an arrow).
For example:
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1)
y = [-5, 10, 25, -10, 30, -300, 20, 30, -10, -300, 0, 4]
x = range(len(y))
ax.bar(x, y, width=1, alpha=0.5)
ymin, ymax = -15, 35
ax.set_ylim(ymin, ymax)
for xbar,ybar in zip(x,y):
if ybar < ymin:
ax.annotate(
ybar,
xy=(xbar+0.5, -14),
xytext=(xbar+0.5, -8),
rotation=90, ha='center', va='center',
arrowprops=dict(arrowstyle="->"))
plt.show()
Related
I need to set the dimension of a chart exactly. I tried this, but the result is not what I expected (both if I set px and cm). In addiction, I would like to know how to export correctly the image.
import numpy as np
plt.rcParams['figure.dpi']=100
# create data
x = ['A', 'B', 'C', 'D']
y1 = np.array([10, 20, 10, 30])
y2 = np.array([20, 25, 15, 25])
y3 = np.array([12, 15, 19, 6])
y4 = np.array([10, 29, 13, 19])
# plot bars in stack manner
cm = 1/2.54 # centimeters in inches
px = 1/plt.rcParams['figure.dpi'] # pixel in inches
plt.figure(figsize=(800*px,1000*px))
plt.bar(x, y1, color='r')
plt.bar(x, y2, bottom=y1, color='b')
plt.bar(x, y3, bottom=y1+y2, color='y')
plt.bar(x, y4, bottom=y1+y2+y3, color='g')
plt.xlabel("Teams")
plt.ylabel("Score")
plt.legend(["Round 1", "Round 2", "Round 3", "Round 4"])
plt.title("Scores by Teams in 4 Rounds")
plt.show()
Dimensions expected: 800px x 1000 px, dpi= 100
I attach here a screenshot from Photoshop of the exported image
Not correct dimensions!
The Figure constructor accepts a tuple (numbers in inches) with a default of 80 dpi. You'll want to pass a dpi argument to change this
from matplotlib.figure import Figure
fig = Figure(figsize=(5, 4), dpi=80)
The above is 5 inches by 4 inches at 80dpi, which is 400px by 320px
if you want 800 by 1000 you can do
fig = Figure(figsize=(8, 10), dpi=100)
Exporting an image is as simple as
fig.savefig("MatPlotLib_Graph.png", dpi = 100)
I have been following the example provided in:
https://matplotlib.org/examples/api/barchart_demo.html
My problem is that I want to add edges to the bars. But when I set the
linewidth=1, edgecolor='black'
parameters, the edges are only applied to the first pair of bars, leaving the remaining pairs unchanged.
"""
========
Barchart
========
A bar plot with errorbars and height labels on individual bars
"""
import numpy as np
import matplotlib.pyplot as plt
N = 5
men_means = (20, 35, 30, 35, 27)
men_std = (2, 3, 4, 1, 2)
ind = np.arange(N) # the x locations for the groups
width = 0.35 # the width of the bars
fig, ax = plt.subplots()
rects1 = ax.bar(ind, men_means, width, color='r', yerr=men_std,linewidth=1, edgecolor='black')
women_means = (25, 32, 34, 20, 25)
women_std = (3, 5, 2, 3, 3)
rects2 = ax.bar(ind + width, women_means, width, color='y', yerr=women_std, linewidth=1, edgecolor='black')
# add some text for labels, title and axes ticks
ax.set_ylabel('Scores')
ax.set_title('Scores by group and gender')
ax.set_xticks(ind + width / 2)
ax.set_xticklabels(('G1', 'G2', 'G3', 'G4', 'G5'))
ax.legend((rects1[0], rects2[0]), ('Men', 'Women'))
def autolabel(rects):
"""
Attach a text label above each bar displaying its height
"""
for rect in rects:
height = rect.get_height()
ax.text(rect.get_x() + rect.get_width()/2., 1.05*height,
'%d' % int(height),
ha='center', va='bottom')
autolabel(rects1)
autolabel(rects2)
plt.show()
Thanks for your help.
David.
I do have a plot that only consists of horizontal lines at certain values when I have a signal, otherwise none. So, I am looking for a way to plot this without the vertical lines. there may be gaps between the lines when there is no signal and I dont want the lines to connect nor do I want a line falling off to 0. Is there a way to plot this like that in matplotlib?
self.figure = plt.figure()
self.canvas = FigureCanvas(self.figure)
axes = self.figure.add_subplot(111)
axes.plot(df.index, df["x1"], lw=1.0, c=self.getColour('g', i), ls=ls)
The plot you are looking for is Matplotlib's plt.hlines(y, xmin, xmax).
For example:
import matplotlib.pyplot as plt
y = range(1, 11)
xmin = range(10)
xmax = range(1, 11)
colors=['blue', 'green', 'red', 'yellow', 'orange', 'purple',
'cyan', 'magenta', 'pink', 'black']
fig, ax = plt.subplots(1, 1)
ax.hlines(y, xmin, xmax, colors=colors)
plt.show()
Yields a plot like this:
See the Matplotlib documentation for more details.
How to create a compact horizontal gauge like for example a thermometer for temperature, barometer for pressure using Matplotlib. The scale of the gauge will be split into ranges; each range denoting high-high, high. low and low-low and a pointer reading the value? Is it possible to create such a gauge in matplotlib?
You could use a colorbar.
For example:
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure(figsize=(8, 2))
ax = fig.add_axes([0.1, 0.4, 0.8, 0.2])
bounds = [-20, -10, 0, 10, 20]
labels = ('low-low', 'low', 'high', 'high-high')
cmap = mpl.cm.coolwarm
norm = mpl.colors.Normalize(vmin=bounds[0], vmax=bounds[-1])
cb = mpl.colorbar.ColorbarBase(
ax,
cmap=cmap,
norm=norm,
orientation='horizontal',
boundaries=bounds,
label='temperature (degrees celcius)',
)
for i, label in enumerate(labels):
xpos = float((2*i + 1))/(2*len(labels))
ax.annotate(label, xy=(xpos, 0.5), xycoords='axes fraction', ha='center', va='center')
plt.show()
Which produces something like this:
For more info see these examples in the matplotlib docs.
I am plotting 3d bar plots using mplot3d:
import numpy as np
import matplotlib
matplotlib.use("Qt4Agg")
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
result=[[0, 0, 5, 5, 14,40,50],
[0, 1, 8, 9, 20,50,70],
[0, 2, 8, 10, 25,60,80],
[0, 5, 10, 20, 40,75,100]]
result = np.array(result, dtype=np.int)
fig=plt.figure()
fig.set_size_inches(6, 4)
ax1=fig.add_subplot(111, projection='3d')
ax1.view_init(25, 280)
matplotlib.rcParams.update({'font.size': 12})
matplotlib.rcParams['font.weight']='normal'
xlabels = np.array(["Count1", "Count3","Count5", "Count6","Count7","Count8","Count9"])
xpos = np.arange(xlabels.shape[0])
ylabels = np.array(["5%","10%","20%","100%"])
ypos = np.arange(ylabels.shape[0])
xposM, yposM = np.meshgrid(xpos, ypos, copy=False)
zpos=result
zpos = zpos.ravel()
dx=0.75
dy=0.5
dz=zpos
ax1.w_xaxis.set_ticks(xpos + dx/2.)
ax1.w_xaxis.set_ticklabels(xlabels)
ax1.w_yaxis.set_ticks(ypos + dy/2)
ax1.set_yticklabels(ylabels)
ax1.w_zaxis.set_ticklabels(["","20%","40%","60%","80%","100%"])
colors = ['b','b','b','b','b','b','b','r','r','r','r','r','r','r','y','y','y','y','y','y','y','g','g','g','g','g','g','g']
ax1.bar3d(xposM.ravel(), yposM.ravel(), dz*0, dx, dy, dz, color=colors)
fig.savefig('tmp.tiff', dpi=300)
plt.close()
and here is what i got:
There are two problems here actually:
1) the y tick labels do not display correctly, they are supposed to be in the middle of the ticks but instead below the ticks. z tick labels are too close to the z ticks.
2) I suppose to use the font size 12 and the dpi should be higher than 300. I could not scale x axis such that the x tick labels fit nicely and do not overlap. I have tried multiply the xpos by 2. However the tick labels still overlap.