Drawing a diagonal line of my matplotlib scatterplot? - matplotlib

I am trying to draw a diagonal line on my figure to demonstrate how my data compares to someone else's, so I want a line representing 1:1 relationship. I'm trying to use plt.plot to do the line between two points but there is no line on my plot. This is my code + the figure. Can anyone tell me why it is not working?
plot23 = sns.regplot(x = Combined['log10(L/L_solar)'], y = Combined['logLum'],
fit_reg=False).set_title('Figure 23: Comparing luminosities')
plt.xlabel('logL from my data', fontsize=13)
plt.ylabel('logL from Drout', fontsize=13)
plt.axis((4, 6, 4, 6))
plt.plot([0,0], [6,6], 'k-')
plt.show()
plot23.figure.savefig("figure23.png")

You made a mistake in using plt.plot. The syntax is
plt.plot(xarray,yarray, ...)
.
This should be :
plt.plot([0,6], [0,6], 'k-')

To draw infinite lines under a specified angle, e.g. 45deg through the origin at (0,0) you can use
plt.axline( (0,0),slope=-1,linestyle='--',color='red')
This line will span the full axes box regardless the data extremes and you don't have to first determine the axis limits or data limits.
This is a generalization of plt.axhline() and plt.axvline(), which are used to draw infinite length horizontal and vertical lines.
Ref: https://matplotlib.org/stable/gallery/pyplots/axline.html

Related

Scaling textplot_wordcloud quanteda

I want to plot features from my quanteda dfm.
When I use the textplot_wordcloud (see code) I get the error:
In wordcloud(x, min_size, max_size, min_count, max_words, ... : Term x could not be fit on page. It will not be plotted.
dfm_joint <- dfm(tokens_skip)
textplot_wordcloud(dfm_joint, min_size = 2, rotation = 0.25, max_words = 100,
color = rev(RColorBrewer::brewer.pal(10, "RdBu")))
I guess it lies within the scaling of the plot but is there any possibility to adjust the plot size within the textplot_wordcloud function? Because the argument "adjust" delivered with the function is just for adapting the size of the words which doesn´t fix the problem.
Thanks very much in advance.

colorbars for grid of line (not contour) plots in matplotlib

I'm having trouble giving colorbars to a grid of line plots in Matplotlib.
I have a grid of plots, which each shows 64 lines. The lines depict the penalty value vs time when optimizing the same system under 64 different values of a certain hyperparameter h.
Since there are so many lines, instead of using a standard legend, I'd like to use a colorbar, and color the lines by the value of h. In other words, I'd like something that looks like this:
The above was done by adding a new axis to hold the colorbar, by calling figure.add_axes([0.95, 0.2, 0.02, 0.6]), passing in the axis position explicitly as parameters to that method. The colorbar was then created as in the example code here, by instantiating a ColorbarBase(). That's fine for single plots, but I'd like to make a grid of plots like the one above.
To do this, I tried doubling the number of subplots, and using every other subplot axis for the colorbar. Unfortunately, this led to the colorbars having the same size/shape as the plots:
Is there a way to shrink just the colorbar subplots in a grid of subplots like the 1x2 grid above?
Ideally, it'd be great if the colorbar just shared the same axis as the line plot it describes. I saw that the colorbar.colorbar() function has an ax parameter:
ax
parent axes object from which space for a new colorbar axes will be stolen.
That sounds great, except that colorbar.colorbar() requires you to pass in a imshow image, or a ContourSet, but my plot is neither an image nor a contour plot. Can I achieve the same (axis-sharing) effect using ColorbarBase?
It turns out you can have different-shaped subplots, so long as all the plots in a given row have the same height, and all the plots in a given column have the same width.
You can do this using gridspec.GridSpec, as described in this answer.
So I set the columns with line plots to be 20x wider than the columns with color bars. The code looks like:
grid_spec = gridspec.GridSpec(num_rows,
num_columns * 2,
width_ratios=[20, 1] * num_columns)
colormap_type = cm.cool
for (x_vec_list,
y_vec_list,
color_hyperparam_vec,
plot_index) in izip(x_vec_lists,
y_vec_lists,
color_hyperparam_vecs,
range(len(x_vecs))):
line_axis = plt.subplot(grid_spec[grid_index * 2])
colorbar_axis = plt.subplot(grid_spec[grid_index * 2 + 1])
colormap_normalizer = mpl.colors.Normalize(vmin=color_hyperparam_vec.min(),
vmax=color_hyperparam_vec.max())
scalar_to_color_map = mpl.cm.ScalarMappable(norm=colormap_normalizer,
cmap=colormap_type)
colorbar.ColorbarBase(colorbar_axis,
cmap=colormap_type,
norm=colormap_normalizer)
for (line_index,
x_vec,
y_vec) in zip(range(len(x_vec_list)),
x_vec_list,
y_vec_list):
hyperparam = color_hyperparam_vec[line_index]
line_color = scalar_to_color_map.to_rgba(hyperparam)
line_axis.plot(x_vec, y_vec, color=line_color, alpha=0.5)
For num_rows=1 and num_columns=1, this looks like:

highlight single contour line

I'm making a simple contour plot and I want to highlight the zero line by making it thicker and changing the color.
cs = ax1.contour(x,y,obscc)
ax1.clabel(cs,inline=1,fontsize=8,fmt='%3.1f')
How do I achieve this?
Thanks :-)
HTH -- this is basically the contour example taken from the matplotlib docs, just with modified level lines
The object that is returned from the contour-method holds a reference to the contour lines in its collections attribute.
The contour lines are just common LineCollections.
In the following code snippet the reference to the contour plot is in CS (that is cs in your question):
CS.collections[0].set_linewidth(4) # the dark blue line
CS.collections[2].set_linewidth(5) # the cyan line, zero level
CS.collections[2].set_linestyle('dashed')
CS.collections[3].set_linewidth(7) # the red line
CS.collections[3].set_color('red')
CS.collections[3].set_linestyle('dotted')
type(CS.collections[0])
# matplotlib.collections.LineCollection
Here's how to find out about the levels, if you didn't explicitly specify them:
CS.levels
array([-1. , -0.5, 0. , 0.5, 1. , 1.5])
There is also a lot of functionality to format individual labels:
CS.labelCValueList CS.labelIndiceList CS.labelTextsList
CS.labelCValues CS.labelLevelList CS.labelXYs
CS.labelFmt CS.labelManual CS.labels
CS.labelFontProps CS.labelMappable CS.layers
CS.labelFontSizeList CS.labelTexts

geometry of colorbars in matplotlib

Plotting a figure with a colorbar, like for example the ellipse collection of the matplotlib gallery, I'm trying to understand the geometry of the figure. If I add the following code in the source code (instead of plt.show()):
cc=plt.gcf().get_children()
print(cc[1].get_geometry())
print(cc[2].get_geometry())
I get
(1, 2, 1)
(3, 1, 2)
I understand the first one - 1 row, two columns, plot first (and presumably the second is the colorbar), but I don't understand the second one, which I would expect to be (1,2,2). What do these values correspond to?
Edit: It seems that the elements in cc do not have the same axes,which would explain the discrepancies. Somehow, I'm still confused with the geometries that are reported.
What's happening is when you call colorbar, use_gridspec defaults to True which then makes a call to matplotlib.colorbar.make_axes_gridspec which then creates a 1 by 2 grid to hold the plot and cbar axes then then cbar axis itself is actually a 3 by 1 grid that has its aspect ratio adjusted
the key line in matplotlib.colorbar.make_axes_gridspec which makes this happen is
gs2 = gs_from_sp_spec(3, 1, subplot_spec=gs[1], hspace=0.,
height_ratios=wh_ratios)
because wh_ratios == [0.0, 1.0, 0.0] by default so the other two subplots above and below are 0 times the size of the middle plot.
I've put what I did to figure this out into an IPython notebook

matplotlib numbers in legend

I have a couple of lines and I want to show a legend. The problem is, I can't use different styles (--, :, -.) because there are too few of them, and I can't use markers (+, *, etc.) because I need them to show some points on the lines.
So the best idea I've come up with is to use numbers. But I can't figure how I can create legends with numbers. I can even draw numbers near lines myself (to place them in the best position), but how can I then draw a legend with the numbers?
I.e. instead of:
-- H
-.- Li
I'd like something like:
1 H
2 Li
Perhaps a little Latex thrown into the mix?
#In which we make a legend; not with lines, but numbers!
import pylab as pl
pl.rc('text', usetex=True)
pl.figure(1)
pl.clf()
ax = pl.subplot(111)
pl.plot(range(0,10), 'k', label = r'\makebox[25]{1\hfill}Bla')
pl.plot(range(1,11), 'k', label = r'\makebox[25]{12\hfill}Bla12')
lgd = pl.legend(handlelength = -0.4)
for k in lgd.get_lines():
k.set_linewidth(0)
pl.draw()
pl.show()
The numbers/labels are aligned by using \makebox with specific width and \hfill to take up the space not used by your labels. Numbers are not automatic, but if you use a loop to draw your lines then you could add a counter to keep track of the numbers.
Don't know if this is part of your requirement, but the lines are removed by setting their linewidth to 0 and making the space reserved in the legend negative. Couldn't find a neater way of doing this as I believe a legend is always meant to show a line (e.g. you can't set numpoints to 0).
You could of course also just add some text in the right spot in your plot and not use a legend at all.