I have a set of ticklabels that are strings on my x axis, and I want to be able to get -> modify -> set them. Say for example I have a plot that looks like this:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(range(1,6), range(5))
plt.xticks(range(1,6), ['a','b','c','d','e']
and I want to change the labels on the x axis to ['(a)','(b)','(c)','(d)','(e)']
what is the simplest/best way to do this? I've tried things like:
labels = ['(%s)' % l for l in ax.xaxis.get_ticklabels()]
ax.xaxis.set_ticklabels(labels)
but ax.xaxis.get_ticklabels() returns matplotlib Text objects as opposed to a list of strings and I'm not sure how to go about modifying them. I also tried using matplotlib.ticker.FuncFormatter but could only get a hold of the numeric positions not the labels themselves. Any would be appreciated.
One more layer to unpeel:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(range(1,6), range(5))
plt.xticks(range(1,6), ['a','b','c','d','e'])
labels = ['(%s)' % l.get_text() for l in ax.xaxis.get_ticklabels()]
ax.xaxis.set_ticklabels(labels)
your code but with l.get_text() in the list comp where there was a l.
Related
Following this I know that I can extract the xticks labels and positions using:
import matplotlib.pyplot as plt
plt.scatter(x_data, y_data)
locs, labels=plt.xticks()
the new variable labels is a matplotlib.cbook.silent_list, which
doesn't behave like a normal list.
Is there a way to access and modify any attribute value of the labels elements?
Specifically I would like to know if I can select a subset of the labels (i.e. slice the silent_list) and modify a particular attribute for that subset.
Here is a toy example:
import numpy as np
import matplotlib.pyplot as plt
x=np.array([1,2,3,4,5,6,7,8])
y=np.random.normal(0, 1, (8, 1))
plt.scatter(x, y)
locs, labels=plt.xticks()
As an example, let say I want to change the labels color to red for all but the first and last element of labels; if I open one of the elements of the variable I can see that there is the attribute _color with value k, which I would like to change in r:
I tried to slice it:
labels[1:-1]
But it returns:
Out[]: [Text(2,0,'2'), Text(4,0,'4'), Text(6,0,'6'), Text(8,0,'8')]
and this is as far as I managed to go.
I couldn't figure out a way to access the attribute and change its value.
NB: I am looking for a general way to access these attributes and change the value, I do not care about changing the labels color specifically. That's just an example.
You might be interested in an alternative solution where you can choose which specific ticks you want to color. Here I have to loop from [1:-1] because the first and the last ticks do not appear on the graph here but they appear in the labels
import numpy as np; np.random.seed(134)
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
x=np.array([1,2,3,4,5,6,7,8])
y=np.random.normal(0, 1, (8, 1))
plt.scatter(x, y)
fig.canvas.draw()
xticks = ax.get_xticklabels()
target_ticks = [1, 3, 6, len(xticks)-2]
for i, lab in enumerate(xticks[1:-1]):
if i+1 in target_ticks:
lab.set_color('r')
I am used to work with plots that change over the time in order to show differences when a parameter is changed. Here I provide an easy example
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
ax.grid(True)
x = np.arange(-3, 3, 0.01)
for j in range(1, 15):
y = np.sin(np.pi*x*j) / (np.pi*x*j)
line, = ax.plot(x, y)
plt.draw()
plt.pause(0.5)
line.remove()
You can clearly see that increasing the paramter j the plot becames narrower and narrower.
Now if I want to do the some job with a counter plot than I just have to remove the comma after "line". From my understanding this little modification comes from the fact that the counter plot is not an element of a tuple anymore, but just an attribute as the counter plot completely "fill up" all the space available.
But it looks like there is no way to remove (and plot again) an histogram. Infact if type
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
ax.grid(True)
x = np.random.randn(100)
for j in range(15):
hist, = ax.hist(x, 40)*j
plt.draw()
plt.pause(0.5)
hist.remove()
It doesn't matter whether I type that comma or not, I just get a message of error.
Could you help me with this, please?
ax.hist doesn't return what you think it does.
The returns section of the docstring of hist (access via ax.hist? in an ipython shell) states:
Returns
-------
n : array or list of arrays
The values of the histogram bins. See **normed** and **weights**
for a description of the possible semantics. If input **x** is an
array, then this is an array of length **nbins**. If input is a
sequence arrays ``[data1, data2,..]``, then this is a list of
arrays with the values of the histograms for each of the arrays
in the same order.
bins : array
The edges of the bins. Length nbins + 1 (nbins left edges and right
edge of last bin). Always a single array even when multiple data
sets are passed in.
patches : list or list of lists
Silent list of individual patches used to create the histogram
or list of such list if multiple input datasets.
So you need to unpack your output:
counts, bins, bars = ax.hist(x, 40)*j
_ = [b.remove() for b in bars]
Here the right way to iteratively draw and delete histograms in matplotlib
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure(figsize = (20, 10))
ax = fig.add_subplot(111)
ax.grid(True)
for j in range(1, 15):
x = np.random.randn(100)
count, bins, bars = ax.hist(x, 40)
plt.draw()
plt.pause(1.5)
t = [b.remove() for b in bars]
I want to access the tick labels on my matplotlib colobar, so that I can manipulate them.
My starting labels may be [-2,-1,0,1,2] for example.
I have used:
locs,oldlabels = plt.xticks()
newlabels = ['a','b','c','d','e']
plt.xticks(locs, newlabels)
This works. But I don't want to manually write in the new labels. I want to access the oldlabels, so that I can have the newlabels as say [2*(-2), 2*(-1), 2*0, 2*1, 2*2].
I just don't know how to 'get at' the oldlabels. I googled everything and tried lots of things, but I'm doing something fundamentally wrong.
I tried to print oldlabels[0], but I get Text(0,0,u'\u22122.0').
EDIT:
I'm currently doing:
new_labels = [1,2,3,4,5,6,7,8,9]
colorbarname.ax.set_xticklabels(new_labels)
which works. But I want to set them as 2 x their old value. How can I do this automatically? I need to extract the old label values, multiply by (say) 2, update the axis labels with the new values.
If your data is not confined to [0,1], I'd recommend using a norm when you pass the data to the colormap instead of changing the data and relabeling the colorbar: http://matplotlib.org/api/cm_api.html?highlight=norm%20colormap#matplotlib.cm.ScalarMappable.norm
However, you can relabel the colorbar by manipulating the underlying axis directly:
import numpy as np
import pylab as plt
A = np.random.random((10,10))
plt.subplot(121)
plt.imshow(A,interpolation='nearest')
cb = plt.colorbar()
oldlabels = cb.ax.get_yticklabels()
print(map(lambda x: x.get_text(),oldlabels))
newlabels = map(lambda x: str(2 * float(x.get_text())), oldlabels)
print(newlabels)
cb.ax.set_yticklabels(newlabels)
plt.show()
oh, and now I find the matplotlib gallery example, nearly the same: http://matplotlib.org/examples/pylab_examples/colorbar_tick_labelling_demo.html
I am plotting 20 different lines on a single plot using matplotlib. I use a for loop for plotting and label every line with its key and then use the legend function
for key in dict.keys():
plot(x,dict[key], label = key)
graph.legend()
But using this way, the graph repeats a lot of colors in the legend. Is there any way to ensure a unique color is assigned to each line using matplotlib and over 20 lines?
thanks
The answer to your question is related to two other SO questions.
The answer to How to pick a new color for each plotted line within a figure in matplotlib? explains how to define the default list of colors that is cycled through to pick the next color to plot. This is done with the Axes.set_color_cycle method.
You want to get the correct list of colors though, and this is most easily done using a color map, as is explained in the answer to this question: Create a color generator from given colormap in matplotlib. There a color map takes a value from 0 to 1 and returns a color.
So for your 20 lines, you want to cycle from 0 to 1 in steps of 1/20. Specifically you want to cycle form 0 to 19/20, because 1 maps back to 0.
This is done in this example:
import matplotlib.pyplot as plt
import numpy as np
NUM_COLORS = 20
cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_prop_cycle(color=[cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS)])
for i in range(NUM_COLORS):
ax.plot(np.arange(10)*(i+1))
fig.savefig('moreColors.png')
plt.show()
This is the resulting figure:
Alternative, better (debatable) solution
There is an alternative way that uses a ScalarMappable object to convert a range of values to colors. The advantage of this method is that you can use a non-linear Normalization to convert from line index to actual color. The following code produces the same exact result:
import matplotlib.pyplot as plt
import matplotlib.cm as mplcm
import matplotlib.colors as colors
import numpy as np
NUM_COLORS = 20
cm = plt.get_cmap('gist_rainbow')
cNorm = colors.Normalize(vmin=0, vmax=NUM_COLORS-1)
scalarMap = mplcm.ScalarMappable(norm=cNorm, cmap=cm)
fig = plt.figure()
ax = fig.add_subplot(111)
# old way:
#ax.set_prop_cycle(color=[cm(1.*i/NUM_COLORS) for i in range(NUM_COLORS)])
# new way:
ax.set_prop_cycle(color=[scalarMap.to_rgba(i) for i in range(NUM_COLORS)])
for i in range(NUM_COLORS):
ax.plot(np.arange(10)*(i+1))
fig.savefig('moreColors.png')
plt.show()
I had a plot with 12 lines, and I found it hard to distinguish lines with similar colours when I tried Yann's technique. My lines also appeared in pairs, so I used the same colour for the two lines in each pair, and used two different line widths. You could also vary the line style to get more combinations.
You could use set_prop_cycle(), but I just modified the line objects after calling plot().
Here is Yann's example with three different line widths:
import matplotlib.pyplot as plt
import numpy as np
NUM_COLORS = 20
cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(NUM_COLORS):
lines = ax.plot(np.arange(10)*(i+1))
lines[0].set_color(cm(i//3*3.0/NUM_COLORS))
lines[0].set_linewidth(i%3 + 1)
fig.savefig('moreColors.png')
plt.show()
Here's the same example with different line styles. Of course you could combine the two if you wanted.
import matplotlib.pyplot as plt
import numpy as np
NUM_COLORS = 20
LINE_STYLES = ['solid', 'dashed', 'dashdot', 'dotted']
NUM_STYLES = len(LINE_STYLES)
cm = plt.get_cmap('gist_rainbow')
fig = plt.figure()
ax = fig.add_subplot(111)
for i in range(NUM_COLORS):
lines = ax.plot(np.arange(10)*(i+1))
lines[0].set_color(cm(i//NUM_STYLES*float(NUM_STYLES)/NUM_COLORS))
lines[0].set_linestyle(LINE_STYLES[i%NUM_STYLES])
fig.savefig('moreColors.png')
plt.show()
To build off of Don Kirkby's answer, if you're willing to install/use seaborn, then you can have colors computed for you:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
NUM_COLORS = 20
LINE_STYLES = ['solid', 'dashed', 'dashdot', 'dotted']
NUM_STYLES = len(LINE_STYLES)
sns.reset_orig() # get default matplotlib styles back
clrs = sns.color_palette('husl', n_colors=NUM_COLORS) # a list of RGB tuples
fig, ax = plt.subplots(1)
for i in range(NUM_COLORS):
lines = ax.plot(np.arange(10)*(i+1))
lines[0].set_color(clrs[i])
lines[0].set_linestyle(LINE_STYLES[i%NUM_STYLES])
fig.savefig('moreColors.png')
plt.show()
Aside from being able to use seaborn's various color palettes, you can get a list of RGB tuples that can be used/manipulated later on if need be. Obviously, you could compute something similar using matplotlib's colormaps, but I find this to be handy.
These answers seemed more complicated than needed. If you are looping through a list to plot lines, then just enumerate on the list and assig color to some point on the colormap. Say you are looping through all the columns from a pandas dataframe:
fig, ax = plt.subplots()
cm = plt.get_cmap('gist_rainbow')
for count, col in enumerate(df.columns):
ax.plot(df[col], label = col, linewidth = 2, color = cm(count*20))
This works because cm is just an iterable dictionary of color numerics. Multiplying those by some factor gets you further along in the colormap (more difference in color).
I am trying to create a plot in matplotlib where the x-values are integers and the y-values are strings. Is it possible to plot data of this type in matplotlib? I examined the documentation and the gallery for matplotlib and could not find any examples of this type.
I have many lists bound to a variable called my_lists. The structure looks like this:
mylists = [765340, 765371, 765310,'MA011',],
[65310, 'MA015'],
[765422, 765422, 24920205, 24920161, 'MA125'],
[765422, 'MA105'],
[765371, 12345, 'MA004']
In each list, all items except the last item are x-values. The last item in each list is a string, which is the single y-value.
How can I plot this is matplotlib? Here was my attempt:
import matplotlib.pyplot as plt
for sub_list in my_lists:
x_value = sub_list[:1]
y_value = sub_list[-1]
plt.plot(x_value, y_value, "ro")
plt.show()
The above code throws me this error:
ValueError: could not convert string to float: MA011
How can integers versus strings be plotted?
You could probably do something like this, where you give each y "string" a unique index value. You may have to fiddle with the spacing for i. Ie. i*2 instead of i to make things look nice. After that you set the tick label for each of those indexes to its corresponding string.
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(9,7))
ax1 = fig.add_subplot(111)
mylists = [[765340, 765371, 765310,'MA011',], [65310, 'MA015'],
[765422, 765422, 24920205, 24920161, 'MA125'],
[765422, 'MA105'],[765371, 12345, 'MA004']]
x = []
y = []
y_labels = []
y_ticks = []
for i,sub_list in enumerate(mylists):
y_labels.append(sub_list[-1])
y_ticks.append(i)
for v in sub_list[:-1]:
x.append(v)
y.append(i)
ax1.set_yticks(y_ticks)
ax1.set_yticklabels(y_labels)
ax1.plot(x, y, "ro")
plt.show()
EDIT:
Sorry I forgot to include the enuemrate call in the for loop. It basically sets the value of i to the index of the current sub_list. Then you use the index instead of the string value as the y-value. After that you replace the label for those y-values with the actual string value.