I would like to change the font size of individual elements in the legend. I know how to change the font properties of the whole legend but I can not figure out a way to change them individually.
For example: In the example below I am plotting two lines and I want the label for line1 to have a bigger font size than line 2
import numpy as np
from matplotlib import pyplot as plt
def line (m , c):
return m*x + c
x = np.arange(0, 10, .25)
plt.plot(x, line(1, 0), label = "Line 1")
plt.plot(x, line(1,1), label = "Line 2")
plt.legend(prop={'family': 'Georgia', 'size': 15})
plt.show()
Using prop={'family': 'Georgia', 'size': 15} I can modify the font size of both the labels simultaneously but is there a way to control the font properties of individual labels in the legend?
Thanks any and all help is appreciated.
Here are some great answers: one is to set the font properties, and the other is to use Latexh notation for the label settings. I will answer with the method of customizing with font properties.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.font_manager import FontProperties
def line (m , c):
return m*x + c
x = np.arange(0, 10, .25)
plt.plot(x, line(1, 0), label = "Line 1")
plt.plot(x, line(1,1), label = "Line 2")
leg = plt.legend(prop={'family': 'Georgia', 'size': 15})
label1, label2 = leg.get_texts()
label1._fontproperties = label2._fontproperties.copy()
label1.set_size('medium')
plt.show()
Related
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.pyplot import figure
plt.style.use('ggplot')
overs = np.arange(1, 51)
india_score = np.random.randint(low = 1, high = 18, size = 50, dtype = 'int16')
plt.bar(overs, india_score, width = 0.80, align = 'center', color = 'orange', label = 'Runs per over')
plt.xlabel('Overs')
plt.ylabel('Score')
plt.title('India Inning')
plt.axis([1, 50, 0, 18])
plt.legend()
plt.grid(color='k', linestyle='-', linewidth=1)
fig = plt.gcf()
fig.set_size_inches(16, 9)
plt.show()
The output looks like this:
If you see the bar chart then runs scored in first over and runs scored in last over stick to the Y axis. How can I give some space between Y axis and my first and last vertical bars. I tried the margins function but that is not working
I searched for similar posts but I was unable to understand the solution as I am new to matplotlib. Any help will be greatly appreciated. Thanks.
Here is how you could do this:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.pyplot import figure
plt.style.use('ggplot')
overs = np.arange(1, 51)
india_score = np.random.randint(low = 1, high = 18, size = 50, dtype = 'int16')
plt.bar(overs, india_score, width = 0.80, align = 'center', color = 'orange', label = 'Runs per over')
plt.xlabel('Overs')
plt.ylabel('Score')
plt.title('India Inning')
plt.axis([1, 50, 0, 18])
plt.legend()
plt.grid(color='k', linestyle='-', linewidth=1)
fig = plt.gcf()
fig.set_size_inches(16, 9)
left, right = plt.xlim()
plt.xlim(left-1, right+1)
plt.show()
left, right = plt.xlim() gets the current limits of the x-axis and plt.xlim(left-1, right+1) sets the new limits by one step further outside relative to the old limits.
I have two values:
test1 = 0.75565
test2 = 0.77615
I am trying to plot a bar chart (using matlplotlib in jupyter notebook) with the x-axis as the the two test values and the y-axis as the resulting values but I keep getting a crazy plot with just one big box
here is the code I've tried:
plt.bar(test1, 1, width = 2, label = 'test1')
plt.bar(test2, 1, width = 2, label = 'test2')
As you can see in this example, you should define X and Y in two separated arrays, so you can do it like this :
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(2)
y = [0.75565,0.77615]
fig, ax = plt.subplots()
plt.bar(x, y)
# set your labels for the x axis here :
plt.xticks(x, ('test1', 'test2'))
plt.show()
the final plot would be like :
UPDATE
If you want to draw each bar with a different color, you should call the bar method multiple times and give it colors to draw, although it has default colors :
import matplotlib.pyplot as plt
import numpy as np
number_of_points = 2
x = np.arange(number_of_points)
y = [0.75565,0.77615]
fig, ax = plt.subplots()
for i in range(number_of_points):
plt.bar(x[i], y[i])
# set your labels for the x axis here :
plt.xticks(x, ('test1', 'test2'))
plt.show()
or you can do it even more better and choose the colors yourself :
import matplotlib.pyplot as plt
import numpy as np
number_of_points = 2
x = np.arange(number_of_points)
y = [0.75565,0.77615]
# choosing the colors and keeping them in a list
colors = ['g','b']
fig, ax = plt.subplots()
for i in range(number_of_points):
plt.bar(x[i], y[i],color = colors[i])
# set your labels for the x axis here :
plt.xticks(x, ('test1', 'test2'))
plt.show()
The main reason your plot is showing one large value is because you are setting a width for the columns that is greater than the distance between the explicit x values that you have set. Reduce the width to see the individual columns. The only advantage to doing it this way is if you need to set the x values (and y values) explicitly for some reason on a bar chart. Otherwise, the other answer is what you need for a "traditional bar chart".
import matplotlib.pyplot as plt
test1 = 0.75565
test2 = 0.77615
plt.bar(test1, 1, width = 0.01, label = 'test1')
plt.bar(test2, 1, width = 0.01, label = 'test2')
I was wondering what the best way to make a y-label where each word in the label can be a different color.
The reason I would like this is because I will be making plots that will contain to curves (Electric Fields and Vector Potential Fields). These curves will be different colors and I would like to show this in the labels. The following is a simplified example, using a previous post (Matplotlib multiple colours in tick labels) to get close. This post does well for the x-axis, however it doesn't space/order the y-axis correctly.
Another post had a similar question (Partial coloring of text in matplotlib), but the first answer didn't seem to work at all anymore and the second answer makes you save the file as a .ps file.
My example code is
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.offsetbox import AnchoredOffsetbox, TextArea, HPacker, VPacker
ax = plt.subplot(111)
x = np.linspace(0,10,10)
y1 = x
y2 = x**2
ax.plot(x,y1,color='r',label='data1')
ax.plot(x,y2,color='b',label='data2')
ax.set_xticks([]) # empty xticklabels
ax.set_yticks([]) # empty xticklabels
# x-axis label
xbox1 = TextArea("Data1-x ", textprops=dict(color="r", size=15))
xbox2 = TextArea("and ", textprops=dict(color="k", size=15))
xbox3 = TextArea("Data2-x ", textprops=dict(color="b", size=15))
xbox = HPacker(children=[xbox1, xbox2, xbox3],
align="center", pad=0, sep=5)
anchored_xbox = AnchoredOffsetbox(loc=3, child=xbox, pad=0., frameon=False,
bbox_to_anchor=(0.3, -0.07),
bbox_transform=ax.transAxes, borderpad=0.)
# y-axis label
ybox1 = TextArea("Data1-y ", textprops=dict(color="r", size=15,rotation='vertical'))
ybox2 = TextArea("and ", textprops=dict(color="k", size=15,rotation='vertical'))
ybox3 = TextArea("Data2-y ", textprops=dict(color="b", size=15,rotation='vertical'))
ybox = VPacker(children=[ybox1, ybox2, ybox3],
align="center", pad=0, sep=5)
anchored_ybox = AnchoredOffsetbox(loc=8, child=ybox, pad=0., frameon=False,
bbox_to_anchor=(-0.08, 0.4),
bbox_transform=ax.transAxes, borderpad=0.)
ax.add_artist(anchored_xbox)
ax.add_artist(anchored_ybox)
plt.legend()
plt.show()
Thanks for the help!
You were almost there. You just need to specify the alignment of the text using ha='left',va='bottom'. (And flip the order of the TextArea objects passed to VPacker).
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.offsetbox import AnchoredOffsetbox, TextArea, HPacker, VPacker
ax = plt.subplot(111)
x = np.linspace(0,10,10)
y1 = x
y2 = x**2
ax.plot(x,y1,color='r',label='data1')
ax.plot(x,y2,color='b',label='data2')
ybox1 = TextArea("Data2-y ", textprops=dict(color="r", size=15,rotation=90,ha='left',va='bottom'))
ybox2 = TextArea("and ", textprops=dict(color="k", size=15,rotation=90,ha='left',va='bottom'))
ybox3 = TextArea("Data1-y ", textprops=dict(color="b", size=15,rotation=90,ha='left',va='bottom'))
ybox = VPacker(children=[ybox1, ybox2, ybox3],align="bottom", pad=0, sep=5)
anchored_ybox = AnchoredOffsetbox(loc=8, child=ybox, pad=0., frameon=False, bbox_to_anchor=(-0.08, 0.4),
bbox_transform=ax.transAxes, borderpad=0.)
ax.add_artist(anchored_ybox)
plt.legend()
plt.show()
Better yet, here is a function that makes the labels using an arbitrary list of strings and colors:
import numpy as np
import matplotlib.pyplot as plt
def multicolor_ylabel(ax,list_of_strings,list_of_colors,axis='x',anchorpad=0,**kw):
"""this function creates axes labels with multiple colors
ax specifies the axes object where the labels should be drawn
list_of_strings is a list of all of the text items
list_if_colors is a corresponding list of colors for the strings
axis='x', 'y', or 'both' and specifies which label(s) should be drawn"""
from matplotlib.offsetbox import AnchoredOffsetbox, TextArea, HPacker, VPacker
# x-axis label
if axis=='x' or axis=='both':
boxes = [TextArea(text, textprops=dict(color=color, ha='left',va='bottom',**kw))
for text,color in zip(list_of_strings,list_of_colors) ]
xbox = HPacker(children=boxes,align="center",pad=0, sep=5)
anchored_xbox = AnchoredOffsetbox(loc=3, child=xbox, pad=anchorpad,frameon=False,bbox_to_anchor=(0.2, -0.09),
bbox_transform=ax.transAxes, borderpad=0.)
ax.add_artist(anchored_xbox)
# y-axis label
if axis=='y' or axis=='both':
boxes = [TextArea(text, textprops=dict(color=color, ha='left',va='bottom',rotation=90,**kw))
for text,color in zip(list_of_strings[::-1],list_of_colors) ]
ybox = VPacker(children=boxes,align="center", pad=0, sep=5)
anchored_ybox = AnchoredOffsetbox(loc=3, child=ybox, pad=anchorpad, frameon=False, bbox_to_anchor=(-0.10, 0.2),
bbox_transform=ax.transAxes, borderpad=0.)
ax.add_artist(anchored_ybox)
ax = plt.subplot(111)
x = np.linspace(0,10,1000)
y1 = np.sin(x)
y2 = np.sin(2*x)
ax.plot(x,y1,color='r')
ax.plot(x,y2,color='b')
multicolor_ylabel(ax,('Line1','and','Line2','with','extra','colors!'),('r','k','b','k','m','g'),axis='both',size=15,weight='bold')
plt.show()
It still takes some fiddling with the positions in the "bbox_to_anchor" keyword.
Hello Python/Matplotlib gurus,
I would like to label the y-axis at a random point where a particular horizontal line is drawn.
My Y-axis should not have any values, and only show major ticks.
To illustrate my request clearly, I will use some screenshots.
What I have currently:
What I want:
As you can see, E1 and E2 are not exactly at the major tick mark. Actually, I know the y-axis values (although they should be hidden, since it's a model graph). I also know the values of E1 and E2.
I would appreciate some help.
Let my code snippet be as follows:
ax3.axis([0,800,0,2500) #You can see that the major YTick-marks will be at 500 intervals
ax3.plot(x,y) #plot my lines
E1 = 1447
E2 = 2456
all_ticks = ax3.yaxis.get_all_ticks() #method that does not exist. If it did, I would be able to bind labels E1 and E2 to the respective values.
Thank you for the help!
Edit:
For another graph, I use this code to have various colors for the labels. This works nicely. energy_range, labels_energy, colors_energy are numpy arrays as large as my y-axis, in my case, 2500.
#Modify the labels and colors of the Power y-axis
for i, y in enumerate(energy_range):
if (i == int(math.floor(E1))):
labels_energy[i] = '$E_1$'
colors_energy[i] = 'blue'
elif (i == int(math.floor(E2))):
labels_energy[i] = '$E_2$'
colors_energy[i] = 'green'
else:
labels_energy.append('')
#Modify the colour of the energy y-axis ticks
for color,tick in zip(colors_energy,ax3.yaxis.get_major_ticks()):
print color, tick
if color:
print color
tick.label1.set_color(color) #set the color property
ax3.get_yaxis().set_ticklabels(labels_energy)
Edit2:
Full sample with dummy values:
#!/bin/python
import matplotlib
# matplotlib.use('Agg') #Remote, block show()
import numpy as np
import pylab as pylab
from pylab import *
import math
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
import matplotlib.font_manager as fm
from matplotlib.font_manager import FontProperties
import matplotlib.dates as mdates
from datetime import datetime
import matplotlib.cm as cm
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
from scipy import interpolate
def plot_sketch():
x = np.arange(0,800,1)
energy_range = range (0,2500,1) #Power graph y-axis range
labels_energy = [''] * len(energy_range)
colors_energy = [''] * len(energy_range)
f1=4
P1=3
P2=2
P3=4
f2=2
f3=6
#Set Axes ranges
ax3.axis([0,800,0,energy_range[-1]])
#Add Energy lines; E=integral(P) dt
y=[i * P1 for i in x]
ax3.plot(x,y, color='b')
y = [i * P2 for i in x[:0.3*800]]
ax3.plot(x[:0.3*800],y, color='g')
last_val = y[-1]
y = [(i * P3 -last_val) for i in x[(0.3*800):(0.6*800)]]
ax3.plot(x[(0.3*800):(0.6*800)],y, color='g')
E1 = x[-1] * P1
E2 = (0.3 * x[-1]) * P2 + x[-1] * (0.6-0.3) * P3
#Modify the labels and colors of the Power y-axis
for i, y in enumerate(energy_range):
if (i == int(math.floor(E1))):
labels_energy[i] = '$E_1$'
colors_energy[i] = 'blue'
elif (i == int(math.floor(E2))):
labels_energy[i] = '$E_2$'
colors_energy[i] = 'green'
else:
labels_energy.append('')
#Modify the colour of the power y-axis ticks
for color,tick in zip(colors_energy,ax3.yaxis.get_major_ticks()):
if color:
tick.label1.set_color(color) #set the color property
ax3.get_yaxis().set_ticklabels(labels_energy)
ax3.axhline(energy_range[int(math.floor(E1))], xmin=0, xmax=1, linewidth=0.25, color='b', linestyle='--')
ax3.axhline(energy_range[int(math.floor(E2))], xmin=0, xmax=0.6, linewidth=0.25, color='g', linestyle='--')
#Show grid
ax3.xaxis.grid(True)
#fig = Sketch graph
fig = plt.figure(num=None, figsize=(14, 7), dpi=80, facecolor='w', edgecolor='k')
fig.canvas.set_window_title('Sketch graph')
ax3 = fig.add_subplot(111) #Energy plot
ax3.set_xlabel('Time (ms)', fontsize=12)
ax3.set_ylabel('Energy (J)', fontsize=12)
pylab.xlim(xmin=0) # start at 0
plot_sketch()
plt.subplots_adjust(hspace=0)
plt.show()
I think you're looking for the correct transform (check this out). In your case, what I think you want is to simply use the text method with the correct transform kwarg. Try adding this to your plot_sketch function after your axhline calls:
ax3.text(0, energy_range[int(math.floor(E1))],
'E1', color='g',
ha='right',
va='center',
transform=ax3.get_yaxis_transform(),
)
ax3.text(0, energy_range[int(math.floor(E2))],
'E2', color='b',
ha='right',
va='center',
transform=ax3.get_yaxis_transform(),
)
The get_yaxis_transform method returns a 'blended' transform which makes the x values input to the text call be plotted in axes units, and the y data in 'data' units. You can adjust the value of the x-data, (0) to be -0.003 or something if you want a little padding (or you could use a ScaledTranslation transform, but that's generally unnecessary if this is a one-off fix).
You'll probably also want to use the 'labelpad' option for set_ylabel, e.g.:
ax3.set_ylabel('Energy (J)', fontsize=12, labelpad=20)
I think my answer to a different post might be of help to you:
Matplotlib: Add strings as custom x-ticks but also keep existing (numeric) tick labels? Alternatives to matplotlib.pyplot.annotate?
It also works for the y-axis.Here is the result:
I copy this example from matplotlib site and now I want to change the font, color and size of the labels, but not the numbers size. And there is a possiblity to just see the numbers that are in the middle and at the end of each side?
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.gca(projection='3d')
X, Y = np.mgrid[0:6*np.pi:0.25, 0:4*np.pi:0.25]
Z = np.sqrt(np.abs(np.cos(X) + np.cos(Y)))
surf = ax.plot_surface(X + 1e5, Y + 1e5, Z, cmap='autumn', cstride=2, rstride=2)
ax.set_xlabel("X-Label")
ax.set_ylabel("Y-Label")
ax.set_zlabel("Z-Label")
ax.set_zlim(0, 2)
plt.show()
Thank you
You can change the font size, color and type by setting text properties when you create the label like this:
ax.set_xlabel("X-Label", size = 40, color = 'r', family = 'fantasy')
You can control which tick marks are displayed using ax.set_xticks.