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)
Related
I am applying this strategy to place legend outside plot. The main difference here is that there are ax1 and ax2 twin axes.
The x value in bbox_to_anchor is set to 0.89 in the following MWE.
As can be seen, the legend box does not display the entire string labels for each color:
MWE:
import matplotlib.pyplot as plt
import numpy as np
suptitle_label = "rrrrrrrr # ttttt yyyyyyy. uuuuuuuuuuuuuuuuuu\n$[$Xx$_{2}$Yy$_{7}]^{-}$ + $[$XxYy$_{2}$(cccc)$_{2}]^{+}$ JjYy model"
# Plotting
fig, ax1 = plt.subplots()
ax1.set_xlabel('Time')
ax1.set_ylabel('y1label')
new_time = np.linspace(1, 8, 100)
j_data = [np.linspace(1, 4, 100), np.linspace(1, 5, 100), np.linspace(1, 6, 100), np.linspace(1, 7, 100)]
sorted_new_LABELS_fmt = ['$[$XxYy$_{2}$(cc)$_{2}]^{+}$', '$[$Xx$_{2}$Yy$_{7}]^{-}$', '$[$XxYy$_{4}]^{-}$', '$[$Xx$_{2}$Yy$_{5}$(cc)$_{2}]^{+}$']
sorted_new_LABELS_colors = ['green', 'red', 'blue', 'orange']
for j,k,c in zip(j_data, sorted_new_LABELS_fmt, sorted_new_LABELS_colors):
ax1.plot(new_time, j, label='%s' % k, color='%s' %c)
All_e_chunks_n = np.linspace(-850, -860, 100)
ax2 = ax1.twinx()
ax2.set_ylabel('y2label')
ax2.plot(new_time, All_e_chunks_n, 'grey', alpha=0.6, linewidth=2.5, label='y2')
# Shrink cccrent axis
box = ax1.get_position()
ax1.set_position([box.x0, box.y0, box.width * 0.9, box.height])
# Put the legend:
fig.legend(loc='center left', bbox_to_anchor=(0.89, 0.5))
fig.suptitle(suptitle_label, fontsize=15)
fig.savefig('mwe.pdf', bbox_inches='tight')
Decreasing this x value and commenting out thebbox_inches='tight' part, yields the following:
For bbox_to_anchor=(0.85, 0.5), this is the result:
For bbox_to_anchor=(0.80, 0.5), this is the result:
For bbox_to_anchor=(0.7, 0.5), this is the result:
I have a code that creates bar plots from a file. I save each plot in a pdf file with a fixed size that I set using rcParams (Landscape A4 format):
fig_size = plt.rcParams["figure.figsize"]
fig_size[0] = 11 # Landscape A4 format inches
fig_size[1] = 8
plt.rcParams["figure.figsize"] = fig_size
This is the code to save the plot as pdf.
plt.savefig(filename, bbox_inches="tight", pad_inches=0.5, transparent=True, dpi=300)
I have tried dpi=100, dpi=600 with no change.
I have about 40 pdf files. However, the size of those pdf slightly varies from 10:35 x 8:36 to almost 10:47x 8:47 inches.
I am talking of the size of the page itself not the disk space that I understand depends on the number of pixel used to plot the file. My files are between 13-17 kb... and that is ok.
What is not ok, is that I can't combine the pdf files in a report as the sizes of the pdf pages do not match.
How can I set up the size of the pdf page to be exactly the same?
below a reproducible script:
"For StackOverFlow"
import matplotlib.pyplot as plt
SMALL_SIZE = 9
MEDIUM_SIZE = 14
BIGGER_SIZE = 18 #28
plt.rc('font', size=SMALL_SIZE) # controls default text sizes
plt.rc('axes', titlesize=SMALL_SIZE) # fontsize of the axes title
plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
plt.rc('xtick', labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc('ytick', labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc('legend', fontsize=SMALL_SIZE) # legend fontsize
plt.rc('axes', titlesize=BIGGER_SIZE)
#x1 = [14, 10, 61, 15, 22]
#y1 = [-10, -2, 1, 8, 12]
#x1 = [0, 1.4, 1.47, 2.3, 2.6]
#y1 = [-1.51, -0.03, 0.04, 0.92, 1.23]
x1=[0.795466667, 1.02, 1.12, 1.155, 1.22, 1.459, 1.47, 1.81]
y1=[-1.50, -0.77, -0.45, -0.34, -0.13, 0.64, 0.68, 1.77]
barWidth = 1.2
r1 = [1.5* i for i in range(0, len(y1))]
fig_size = plt.rcParams["figure.figsize"]
fig_size[0] = 11 #fig_size[0] = 11.69
fig_size[1] = 8 #fig_size[1] = 8.27
plt.rcParams["figure.figsize"] = fig_size
plt.margins(0.005, 0.005)
plt.bar(r1,y1, align='center', color='#9E0032', width=barWidth)
plt.xlabel('Z Code', fontweight='bold')
plt.ylabel('\n Z Value', fontweight='bold')
# Create names on the x-axis
plt.xticks(r1, x1, fontweight='bold')
plt.yticks(fontweight='bold')
title = "Specimen1"
plt.title(title, fontweight='bold')
filename = title + ".pdf"
#plt.savefig(filename, bbox_inches="tight", pad_inches=0.5, transparent=True, dpi=300)
plt.savefig(filename, pad_inches=0.5, transparent=True, dpi=300)
plt.show()
Thank you for the help
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 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()
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.