I would like to position a single boxplot at a custom position like so:
import pylab as plt
import numpy as np
a=np.random.randn(1000)
plt.boxplot(a, positions=np.array([2.]))
but it always appears at 1. Note that plt.violinplot(a, positions=np.array([2.])) works as expected.
I believe it is plotted at the correct position, it's just that the label on the axis is still set to 1. You can see this if you try to plot something else on the axes. For instance, if you do pyplot.plot([1, 2, 3], [3, 0, -3]) you will see that the middle of line crosses through the middle of the boxplot.
This means things will show up in the right places if you're plotting other stuff on the same axes as the boxplot. If you're not plotting anything else on the same axes, it doesn't really matter where the boxes are actually located; you can just set the labels directly by using the labels argument to boxplot.
Related
In the following code, I generate a scatterplot where the legend is manually placed:
#!/usr/bin/env python3
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
frame = frame = pd.DataFrame({"x": [1, 2, 3, 4], "y": [4, 3, 2, 1]})
ax = frame.plot.scatter(x="x", y="y", label="dots")
plt.savefig("dots.pdf")
for y in [0.6, 0.7, 0.8]:
ax.legend(bbox_to_anchor=(0.5, y), bbox_transform=ax.transAxes)
plt.savefig("dots_{}.png".format(y))
It looks like the legend does not obey the placement instructions when it would make it hide a point:
Is there a way to avoid this? I mean, how to really force the placement of the legend?
You may be interested in reading my answer to "How to put the legend out of the plot". While it handles the case of putting the legend outside of the plot, most of it is applicable to placing the legend just anywhere, including inside the plot.
Most imporantly, the legend position is determined by the loc parameter. If you do not specify this parameter in the call to legend(), matplotlib will try to place the legend whereever it thinks it's best, (default is loc ="best").
In case you want to place the legend at a certain position, you may specify the coordinates of its lower left corner to loc:
ax.legend(loc=(0.5, 0.6))
If you want to specify another corner of the legend to be at a certain position, you need to specify the corner with the loc argument and the position using bbox_to_anchor:
ax.legend(loc="upper right", bbox_to_anchor=(0.5, 0.6))
I am currently creating a graph that that analyzes the correlation of absorption and concentration (Beer's law). While creating the graph, I've ran into a few problems, and I am now stuck. My plots are not showing up within my graph. Is it due to placement error? If possible, I would like to leave the ticks, labels, and title in the same (or similar format). Sorry in advance for the sloppiness, trying to get the function down before I make it pretty. But anyways, here is the code:
#importing matplotlib to create a graph
import matplotlib.pyplot as plt
#ploting out the points while labeling the graph
plt.plot([1.95E-06, 9.75E-06, 1.95E-05, 9.75E-05, 1.95E-04, 9.75E-04, 1.95E-
03],[0.2,0.4,0.6,0.8,1.0,1.2,1.4])
plt.xticks([1, 2, 3, 4, 5, 6, 7], [str('1.95E-03'), str('9.75E-04'),
str('1.95E-04'), str('9.75E-05'),str('1.95E-05'), str('9.75E-06'),
str('1.95E-06')])
plt.title('Red')
plt.ylabel('Absorption')
plt.xlabel('Concentration')
plt.grid(True)
plt.show()
Your xticks are completely out of the range where your data lives. Remove the line which sets the xticks and your plot is fine
import matplotlib.pyplot as plt
plt.plot([1.95E-06, 9.75E-06, 1.95E-05, 9.75E-05, 1.95E-04, 9.75E-04, 1.95E-03],
[0.2,0.4,0.6,0.8,1.0,1.2,1.4])
plt.title('Red')
plt.ylabel('Absorption')
plt.xlabel('Concentration')
plt.grid(True)
plt.show()
If you want to use your custom ticks, you need to set them in the data range, i.e. somewhere between 0 and 0.002 and not between 1 and 7.
Your data has x values well below 0.01, while your ticks start at 1, so your data will be to the left of the plot. I would suggest using a logarithmic x axis, just like the example below. This will also fix the problem with the x values being of different orders of magnitude. Note that I also put the tick strings in reverse order, assuming that you mistakenly wrote them the other way round. If not, please just go ahead and re-reverse them!
#importing matplotlib to create a graph
import matplotlib.pyplot as plt
x = [1.95e-06, 9.75e-06, 1.95e-05, 9.75e-05, 1.95e-04, 9.75e-04, 1.95e-03]
#ploting out the points while labeling the graph
plt.semilogx(x ,[0.2,0.4,0.6,0.8,1.0,1.2,1.4])
plt.xticks(x, [str('1.95E-03'), str('9.75E-04'), str('1.95E-04'), str('9.75E-05'),str('1.95E-05'), str('9.75E-06'), str('1.95E-06')], rotation=45)
plt.title('Red')
plt.ylabel('Absorption')
plt.xlabel('Concentration')
plt.grid(True)
plt.tight_layout()
plt.savefig('points.png')
plt.show()
The first argument to plt.xticks should be x-coords (not tick indexes).
It's easier to ask this with a figure. At the moment i obtain the following boxplot graph using matplotlib:
Is there a way to obtain a figure like that, but with each box in a position coherent with the corresponding x-axis number (like in a normal scatter plot, but with boxes instead of points)?
At the moment the numbers on the x-axis are added by means of the labels= argument.
You need to specify the positions argument to the boxplot constructor.
from matplotlib import pyplot as plt
plt.boxplot([[1,4],[2,5],[3,6]], positions=[2,4,5.5])
By default it uses the values [1, 2, ..., n] but you can specify a different x position for each bar and the xticks will be updated automatically.
I have a pair of lists of numbers representing points in a 2-D space, and I want to represent the y/x ratios for these points as a 1-dimensional heatmap, with a diverging color map centered around 1, or the logs of my ratios, with a diverging color map centered around 0.
How do I do that?
My current attempt (borrowing somewhat from Heatmap in matplotlib with pcolor?):
from matplotlib import numpy as np
import matplotlib.pyplot as plt
# There must be a better way to generate arrays of random values
x_values = [np.random.random() for _ in range(10)]
y_values = [np.random.random() for _ in range(10)]
labels = list("abcdefghij")
ratios = np.asarray(y_values) / np.asarray(x_values)
axis = plt.gca()
# I transpose the array to get the points arranged vertically
heatmap = axis.pcolor(np.log2([ratios]).T, cmap=plt.cm.PuOr)
# Put labels left of the colour cells
axis.set_yticks(np.arange(len(labels)) + 0.5, minor=False)
# (Not sure I get the label order correct...)
axis.set_yticklabels(labels)
# I don't want ticks on the x-axis: this has no meaning here
axis.set_xticks([])
plt.show()
Some points I'm not satisfied with:
The coloured cells I obtain are horizontally-elongated rectangles. I would like to control the width of these cells and obtain a column of cells.
I would like to add a legend for the color map. heatmap.colorbar = plt.colorbar() fails with RuntimeError: No mappable was found to use for colorbar creation. First define a mappable such as an image (with imshow) or a contour set (with contourf).
One important point:
matplotlib/pyplot always leaves me confused: there seems to be a lot of ways to do things and I get lost in the documentation. I never know what would be the "clean" way to do what I want: I welcome suggestions of reading material that would help me clarify my very approximative understanding of these things.
Just 2 more lines:
axis.set_aspect('equal') # X scale matches Y scale
plt.colorbar(mappable=heatmap) # Tells plt where it should find the color info.
Can't answer your final question very well. Part of it is due to we have two branches of doing things in matplotlib: the axis way (axis.do_something...) and the MATLAB clone way plt.some_plot_method. Unfortunately we can't change that, and it is a good feature for people to migrate into matplotlib. As far as the "Clean way" is concerned, I prefer to use whatever produces the shorter code. I guess that is inline with Python motto: Simple is better than complex and Readability counts.
Up until recently I have been using Mathematica for my plots. Although it was a real pain and everything had to be done manually, the results where very close to what I wanted. One example is the following:
I really like the grey rounded rectangle in the background of the colorbar. While everything had to be adjusted manually in Mathematica, matplotlib is a lot more automatic and already produced nice results.
But there are still two problems I have:
I don't know how to do a rounded rectangle in the background. I looked at the fancybbox patch but didn't get it to work with the colorbar as I want it to. What is the best way to get something like the Mathematica box? For the legend in plots there seems to be a fancy bbox option... but not for colorbars
When I use the "lesser sign" (<) the label of colorbar moves too far to the right. How can I adjust this (maybe even "in-between" the numbers as in the Mathematica plot)?
I am looking forward to any suggestions pointing in the right direction :).
To your second question: you can use a negative labelpad value to move the label back towards the ticklabels, like this:
import numpy as np
import matplotlib.pyplot as plt
data = np.linspace(0, 10, num=256).reshape(16,16)
cf = plt.contourf(data, levels=(0, 2.5, 5, 7.5, 10))
cb = plt.colorbar(cf)
cb.set_ticklabels([r'$<10^{0}$', 1, 2, r'$10^{14}$', r'$10^{14}+12345678$'])
cb.set_label(r'$n_e$ in $m^{-3}$', labelpad=-40, y=0.45)
plt.show()
Using the parameter y, you can additionally move the label up or down for better symmetry.
The argument of labelpad is given in points (1/72 inch). y accepts values in [0, 1], 0.0 is the lower border and 1.0 the upper.
The result: