Padding text in matplotlib.text - python-3.x

I am looking for a reasonable way to pad text for matplotlib.text. I saw the bbox has a nice pad option but it does only pad the box and does not move the text. Also strangely enough bbox={'linestyle':'None'} does not remove the box line, however, other linestyles are working as expected. Any suggestions?
Use case is relative positioning of text on the plotting area. Using coordinates (1,0.5) puts it too close to the plotting boundary line to look good, and somehow I am reluctant to do (0.99,0.5). That would require change if someone changes fontsize etc.

One option is to use annotate(), which is more flexible than text. You can easily offset the text from the anchor point by a certain number of points (or pixels).
fig, ax = plt.subplots()
ax.annotate('test', xy=(1,0.5), xytext=(-5,0), xycoords='axes fraction', textcoords='offset points', ha='right')

Related

Extract the 3×3image segment from the input image centred around the position (x,y)

I want to ask how to Extract the a n×n image segment from an input image centered around the position (x,y), the image has format like this [[num,num,num],[num,numm,num],[num,num,num]........], size of image is about 10 * 10. Thank you !
I do really recommend using numpy, when working with multidimensional arrays/when you want to manipulate these arrays, but here you go, a numpy solution and a solution without numpy.
import numpy as np
img = np.array([[1,2,3,4,5],[2,3,4,5,6],[3,4,5,6,7],[4,5,6,7,8],[5,6,7,8,9]])
print('img:\n',img,'\n')
partOfImage = img[0:3,0:3]
print('partOfImage:\n',partOfImage)
img = [[1,2,3,4,5],[2,3,4,5,6],[3,4,5,6,7],[4,5,6,7,8],[5,6,7,8,9]]
noNumpy =[[img[i][j] for j in range(0,3)] for i in range(0,3)]
print(noNumpy)
Question. So you wish to find the center of an image, expand 1 pixel left, left down, down, right down, right, right up, up, and left up to get an image from the middle of your sample. Correct? I do not have a code example, but a conceptual comment.
Fixed spatial images normally start their addressing at upper left for 0,0. Because of their even numbers of pixels approach, it's near-impossible to find a "middle". So finding a "middle pixel" means you need to apply a percentage and choose the nearest "whole pixel" to the choice. Then expand to your 3x3 dimensions.

How to clip vega-lite text inside a rect?

In a webpage created with node/webpack, vega-lite, and vegaEmbed, I have a layer with rect marks with short annotations inside them using text marks. I'd like to clip the text to its surrounding rect but haven't figured out a way to do this and hope someone can point me in the right direction.
I realize text has a limit property in pixel units. If I could determine the pixel units of my rect marks (I don't know how to do this), using limit seems like a reasonable approach.
Also, if I knew the pixel extents of my rectangle, I can then write code to align the text within the rect which would be desirable. Currently I just use the same x as the rect, with a dx offset.
I've read about background for text which is a similar problem, but not the same.

Matplotlib Text artist - how to get size? (not using pyplot)

Background
I've moved some code to use matplotlib only, instead of pyplot (The reason is it's generating png files in multi-process with futures, and pyplot isn't thread/process safe that way).
So I'm creating my figure and axis via matplotlib.Figure(), not via pyplot.
I've got some code that draw's a text 'table' on a figure, with one side right justified and the other left. In order to keep the spacing between the two sides constant, I was previously using get_window_extent() on my left-side text artist to figure out the location of the right hand side:
# draw left text at figure normalised coordinates, right justified
txt1 = figure.text(x, y, left_str,
ha='right', color=left_color, fontsize=fontsize)
# get the bounding box of that text - this is in display coords
bbox = txt1.get_window_extent(renderer=figure.canvas.get_renderer())
# get x location for right hand side offset from left's bbox
trans = figure.transFigure.inverted()
xr, _ = trans.transform((bbox.x1 + spacing, bbox.y0))
# draw right side text, using lhs's y value
figure.text(xr, y, right_str,
ha='left', color=right_color, fontsize=fontsize)
Problem
My problem is now that I'm not using pyplot, the above code fails to work, because figure.canvas.get_renderer() fails to return a renderer, as I haven't set one, and am simply using Figure.savefig(path) to save my file when I'm done.
So is there a way to find out the bounding box size of an Artist in a Figure without having a renderer set?
From looking at legend, which allows you to use a bounding box line with variable text size, I'm presuming there is, but I can't find how.
I've had a look at https://matplotlib.org/3.1.3/tutorials/intermediate/artists.html, and also tried matplotlib.artist.getp(txt1) on the above, but didn't find any seemingly helpful properties.

Matplotlib using text instead of marker BUT can't be the best way to do it?

I would just like to make sure I am on the right track here as this seems to be pretty cumbersome for Matplotlib. I want to use a label as a marker on a plot and have it working to some degree. It uses mathtext BUT I wonder if there isn't another way to do it? Here is the code.
import matplotlib.pyplot as plt
x = []
y = []
symbol = "AAPL"
x = range(5)
y = [5,10,12,15,11]
plt.plot(x,y,lw=2.5,color='r',linestyle='solid',marker=r"$ {} $".format(symbol),markersize=25)
plt.show()
I am not 100% sure what you want, but below I have listed a couple of options that I am aware of for putting text into plots at specific locations (essentially what a marker is).
1) you can uses text/characters as markers through unicode. This is done by adding the unicode value within mathtext characters. E.g. take your example code; you can make the marker a unicode character by adding a 'u' before the string (unneeded in python 3) and then a '\u' and a 4 digit number. this will produce a unicode marker. Not all will work, as it depends on whether your system's font supports it. You can find a long list of them here: http://unicode-table.com/en/#latin-extended-a
plt.plot(x,y,lw=2.5,color='r',linestyle='solid',marker=u'$\u2609$',markersize=25)
\u2609 will produce a 'sun', i.e. a circle with a dot in its centre.
2) plt.text(...) using this function you can add text of your choice to the coordinate you specify.
http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.text
I believe the coordinate will correspond to the bottom left corner of the text box, but you can play around with it to make absolutely sure if you want. E.g.
plt.text(x,y,'string',fontsize=18)
However, this must be done on individual points and will not plot a line over the data; it does not work like 'plot' although you could always brute force a line over the top with a subsequent line plot. This method is more of a pain and hardly optimal but it will do the job and is quite flecible if you want a string for a marker.

SVG Text-anchor top left

By default, the anchor for the text element in SVG is at the bottom left, but I want it to be at the top left, since I am also creating a rectangle to act as the background for the text, but it is displayed incorrectly since the text is higher than the rectangle (because rectangle anchor/offset is at the top left). Is there a way to fix this, so both text and rectangle can be drawn at same coordinates and be displayed in the same location.
The dominant-baseline property/attribute worked for me:
svg {
dominant-baseline: hanging;
}
The coordinates (x and y) you supply for text elements is used as the baseline of the text. This makes sense because if there is text with varying font sizes on the same line, you would want their baselines to line up.
There is no "automatic" way to do what you want. SVG elements are always absolutely positioned.
You will just have to move the text down a bit by making the y coordinate a bit larger.
Alternatively, you could add a dy attribute to shift the text down a bit. Or even use a transform attribute to do the same. But using either of those methods wouldn't really be simplifying the process for you.

Resources