Why paragraph lines have different height? - text

I want to calculate how much height my text requires with N number of lines. I assumed all lines of paragraph have the same height, but this code shows different result:
#Preview
#Composable
fun LineHeightPreview() {
Text(
modifier = Modifier
.fillMaxWidth(),
// text = "Title\ntitle\nTITLE\nTitle", // text # 1
// text = "title\ntitle\ntitle\ntitle", // text # 2
// text = "title\ntitle", // text # 3
text = "title", // text # 4
textAlign = TextAlign.Center,
onTextLayout = {
val lines = it.lineCount
for (i in 0 until lines) {
val lineHeight = it.multiParagraph.getLineHeight(i)
Log.d("onTextLayout", "Line #$i, height = $lineHeight")
}
}
)
}
Here are the lines height for different texts:
// text # 1
D/onTextLayout: Line #0, height = 48.0
D/onTextLayout: Line #1, height = 43.0
D/onTextLayout: Line #2, height = 43.0
D/onTextLayout: Line #3, height = 44.0
// text # 2
D/onTextLayout: Line #0, height = 48.0
D/onTextLayout: Line #1, height = 43.0
D/onTextLayout: Line #2, height = 43.0
D/onTextLayout: Line #3, height = 44.0
// text # 3
D/onTextLayout: Line #0, height = 48.0
D/onTextLayout: Line #1, height = 44.0
// text # 4
D/onTextLayout: Line #0, height = 49.0
It seems that MultiParagraph ignores the first line top offset and the last line bottom offset. The rest of the lines are the same height as intended. How can I get these offsets? Or maybe is there another way to compute how much height my text requires with N number of lines (e.g. how much height text "small_text" requires if it repeats some times)?

Related

How to crop a square image from normalized vertices

I'm using this code to identify tops and bottoms of photographs:
( as of now I only have it working for tops. one thing at a time ;) )
def get_file(path):
client = vision.ImageAnnotatorClient()
for images in os.listdir(path):
# # Loads the image into memory
with io.open(images, "rb") as image_file:
content = image_file.read()
image = types.Image(content=content)
objects = client.object_localization(image=image).localized_object_annotations
im = Image.open(images)
width, height = im.size
print("Number of objects found: {}".format(len(objects)))
for object_ in objects:
if object_.name == "Top":
print("Top")
l1 = object_.bounding_poly.normalized_vertices[0].x
l2 = object_.bounding_poly.normalized_vertices[0].y
l3 = object_.bounding_poly.normalized_vertices[2].x
l4 = object_.bounding_poly.normalized_vertices[3].y
left = l1 * width
top = l2 * height
right = l3 * width
bottom = l4 * height
im = im.crop((left, top, right, bottom))
im.save('new_test_cropped.tif', 'tiff')
im.show()
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Script to automatically crop images based on google vision predictions of 'tops' and 'bottoms'")
parser.add_argument('--path', help='Include the path to the images folder')
args = parser.parse_args()
get_file(args.path)
The images are opened, clothing is identified, and then the images are cropped and saved to a new file. (granted as of now they are being overwritten within the loop, but I'll fix that later)
What I cant figure out, is how to make the crop a 1:1 ratio. I need to save them out as square-cropped to be put on our website.
I'll be honest, the normalized_vertices make no sense to me. Hence why I'm having trouble.
Starting image:
Output:
Desired Output:
"Normalized" means the coordinates are divided by the width or height of the image, so normalized coordinates [1, 0.5] would indicate all the way (1) across the image and halfway down (0.5).
For a 1:1 aspect ratio you want right - left to be equal to top - bottom. So you want to find out which dimension (width or height) you need to increase, and by how much.
height = abs(top - bottom)
width = abs(right - left)
extrawidth = max(0, height - width)
extraheight = max(0, width - height)
If height > width, we want to increase width but not height. Since height - width > 0, the correct value will go into extrawidth. But because width - height < 0, extraheight will be 0.
Now let's say we want to increase the dimensions of our image symmetrically around the original crop rectangle.
top -= extraheight // 2
bottom += extraheight // 2
left -= extrawidth // 2
right += extrawidth // 2
And finally, do the crop:
im = im.crop((left, top, right, bottom))
For your image, let's say you get left = 93, right = 215, top = 49, and bottom = 205
Before:
After:

Resizing both height and width textInput in kivy

<AutoResizedText>
GridLayout:
cols:1
size: root.width, root.height
TextInput:
multiline:True
size_hint:(None,None)
size:(self.height,self.minimum_height )
text: "hello my cat"
I'm currently trying to get a TextInput that expands in width and height based upon what string it contains within it. I've been able to get the height to expand alongside the text. But not the width for some reason. self.minimum_width does not appear to be a method when I try to replace self.height with self.minimum_height
The TextInput can't do what you want without some modifications. The standard TextInput needs you to set the width, then it will fill its text field, splitting the text as needed to keep it to that width, and calculating a minimum_height based on that.
Here is a version of TextInput that I have modified to do what I think you want:
class MyTextInput(TextInput):
minimum_width = NumericProperty(0)
def _split_smart(self, text):
# modified to always split on newline only
lines = text.split(u'\n')
lines_flags = [0] + [FL_IS_LINEBREAK] * (len(lines) - 1)
return lines, lines_flags
def _refresh_text(self, text, *largs):
# this is modified slightly just to calculate minimum_width
# Refresh all the lines from a new text.
# By using cache in internal functions, this method should be fast.
mode = 'all'
if len(largs) > 1:
mode, start, finish, _lines, _lines_flags, len_lines = largs
# start = max(0, start)
cursor = None
else:
cursor = self.cursor_index()
_lines, self._lines_flags = self._split_smart(text)
_lines_labels = []
_line_rects = []
_create_label = self._create_line_label
# calculate minimum width
min_width = 0
for x in _lines:
lbl = _create_label(x)
min_width = max(min_width, lbl.width)
_lines_labels.append(lbl)
_line_rects.append(Rectangle(size=lbl.size))
self.minimum_width = min_width + self.padding[0] + self.padding[2]
if mode == 'all':
self._lines_labels = _lines_labels
self._lines_rects = _line_rects
self._lines = _lines
elif mode == 'del':
if finish > start:
self._insert_lines(start,
finish if start == finish else (finish + 1),
len_lines, _lines_flags,
_lines, _lines_labels, _line_rects)
elif mode == 'insert':
self._insert_lines(
start,
finish if (start == finish and not len_lines)
else (finish + 1),
len_lines, _lines_flags, _lines, _lines_labels,
_line_rects)
min_line_ht = self._label_cached.get_extents('_')[1]
# with markup texture can be of height `1`
self.line_height = max(_lines_labels[0].height, min_line_ht)
# self.line_spacing = 2
# now, if the text change, maybe the cursor is not at the same place as
# before. so, try to set the cursor on the good place
row = self.cursor_row
self.cursor = self.get_cursor_from_index(self.cursor_index()
if cursor is None else cursor)
# if we back to a new line, reset the scroll, otherwise, the effect is
# ugly
if self.cursor_row != row:
self.scroll_x = 0
# with the new text don't forget to update graphics again
self._trigger_update_graphics()
def on_text(self, *args):
# added to update minimum width on each change
cc, cr = self.cursor
text = self._lines[cr]
lbl = self._create_line_label(text)
self.minimum_width = max(self.minimum_width, lbl.width + self.padding[0] + self.padding[2])
This version of TextInput has a minimum_width property. I have modified _smart_split() so that it only splits lines on newlines. The _refresh_text() is almost identical to the original, but includes a calculation of minimum_width. I added a on_text() method to update minimum_width each time the text changes. So, now you can use self.minimum_width and self.minimum_height to size the Widget as:
MyTextInput:
multiline: True
size_hint:(None,None)
size:(self.minimum_width, self.minimum_height)
text: "hello my cat"

Draw a line of certain length in Pine Script

I'm trying to develop a Pivot Points indicator on Trading View v4.0 and an issue I'm facing is that the pivot lines are drawn only up to the current bar. The behavior I want is that I want the line to extend for the duration of the period. For example, the weekly pivot line should extend from Monday to Sunday even if today is Monday.
Below is the code I'm using as well as the result:
// Function outputs 1 when it's the first bar of the D/W/M/Y
is_newbar(res) =>
ch = 0
if(res == 'Y')
t = year(time('D'))
ch := change(t) != 0 ? 1 : 0
else
t = time(res)
ch := change(t) != 0 ? 1 : 0
ch
bars_since_week = 0
bars_since_week := is_newbar(pp_res_week) ? 0 : bars_since_week[1] + 1
vpp_p_week = line.new(bar_index[min(bars_since_week, 300)], PP_week, bar_index, PP_week, color=color.black, width = 2, style = line.style_solid, extend = extend.none)
vs1_p_week = line.new(bar_index[min(bars_since_week, 300)], S1_week, bar_index, S1_week, color=color.black, width = 2, style = line.style_solid, extend = extend.none)
vs2_p_week = line.new(bar_index[min(bars_since_week, 300)], S2_week, bar_index, S2_week, color=color.black, width = 2, style = line.style_solid, extend = extend.none)
vs3_p_week = line.new(bar_index[min(bars_since_week, 300)], S3_week, bar_index, S3_week, color=color.black, width = 2, style = line.style_solid, extend = extend.none)
vr1_p_week = line.new(bar_index[min(bars_since_week, 300)], R1_week, bar_index, R1_week, color=color.black, width = 2, style = line.style_solid, extend = extend.none)
vr2_p_week = line.new(bar_index[min(bars_since_week, 300)], R2_week, bar_index, R2_week, color=color.black, width = 2, style = line.style_solid, extend = extend.none)
vr3_p_week = line.new(bar_index[min(bars_since_week, 300)], R3_week, bar_index, R3_week, color=color.black, width = 2, style = line.style_solid, extend = extend.none)
Also, below is the behavior I would expect - notice the longer lines:
It's not a simple matter, at least not the way it's done here ) There is perhaps a better way, but haven't figured out any:
You'll need to work with xloc = xloc.bar_time to be able to draw a line in the future when you need to.
Use the f_avgDilationOf() from the PineCoders MTF Selection Framework to know the average number of chart bars in the dilation of the higher TF (on a 24/7 market, this would be 7 on a daily chart if HTF=1W).
Figure out if current chart bars (current being the one the script is executing on) are included in the last dilation of the HTF. We need this info because when that is true, we will project the line in the future.
//#version=4
study("Periodic lines", "", true)
htf = input("W", type = input.resolution)
// Returns the average number of current chart bars in the given target HTF resolution (this reflects the dataset's history).
f_avgDilationOf(_res) =>
// _res: resolution of any TF (in "timeframe.period" string format).
b = barssince(change(time(_res)))
cumTotal = cum(b == 0 ? b[1] + 1 : 0)
cumCount = cum(b == 0 ? 1 : 0)
cumTotal / cumCount
// Period change detection.
pChange(res) =>
change(time(res == 'Y' ? 'D' : res))
// Get some previous value from last HTF period.
pHi = security(syminfo.tickerid, htf, high[1], lookahead = barmerge.lookahead_on)
// Verify if current charts bars are part of the last dilation of HTF.
lastPBar = security(syminfo.tickerid, htf, barstate.islast, lookahead = barmerge.lookahead_on)
// Get avg no of chart bars in one dilation of HTF.
dilation = round(f_avgDilationOf(htf))
timeDelta = time - time[1]
var line pHiLine = na
// Holds bar index where a new line is created.
var pHiBar = 0
if pChange(htf)
// Extend old line for the last bar before creating a new one.
line.set_xy2(pHiLine, time, pHi[1])
// Save bar index on transition.
pHiBar := bar_index
// Create new line.
pHiLine := line.new(time, pHi, time + timeDelta, pHi, xloc.bar_time, color = color.black, width = 2)
// Make type of the 2 `if` blocks the same.
float(na)
else
// We are not on a transition; prolong line until next transition.
line.set_xy2(pHiLine, time, pHi)
float(na)
// If we are in the last bars of the HTF resolution's dilation, project line into the future with remaining bars in average no of bars in dilation.
if lastPBar
line.set_xy2(pHiLine, time + (timeDelta * (dilation - (bar_index - pHiBar))), pHi)
Caveat: Haven't forward-tested this, so unsure how it'll perform in those conditions.

pygame - How to read a file and blit the text onto the screen

So I have been reading files lately and a challenge was to read a file and then screen.blit all of the text in pygame.
import pygame
import sys
pygame.init()
screenSizeX = 1080
screenSizeY = 720
screenSize = (screenSizeX,screenSizeY)
screen = pygame.display.set_mode(screenSize,0)
pygame.display.set_caption("Display Text")
WHITE = (255,255,255)
GREEN = (0,255,0)
BLUE = (0,0,255)
RED = (255,0,0)
YELLOW = (255,255,0)
BLACK = (0,0,0)
x = 100
y = 100
file = input("Enter the name of the file you want to display(no quotes) ")
file = str(file)
inputedFile = open(file, "r")
def textOutput(line):
fontTitle = pygame.font.SysFont("Arial", 72)
textTitle = fontTitle.render(line, True, GREEN)
screen.blit(textTitle, (x,y))
pygame.display.update()
for line in inputedFile:
text = line
go = True
while go:
for event in pygame.event.get():
if event.type ==pygame.QUIT:
go = False
screen.fill(WHITE)
fontTitle = pygame.font.SysFont("Arial", 72)
textTitle = fontTitle.render(text, True, GREEN)
screen.blit(textTitle, (x,y))
pygame.display.update()
inputedFile.close()
pygame.quit()
sys.exit()
So this kind of works. It will display the last line of the file you input for it to read. So I was wondering if there was a way to make it display every single line from a text file. It also display a rectangle after the line, which I think has something to do with a \n at the end of the line of text.
In this loop
for line in inputedFile:
text = line
you actually overwrite text all the times with the last line. You would actually want to append the new lines. Like this:
text = []
for line in inputedFile:
text.append(line)
text = '\n'.join(text)
You can also try to use the read function, as described here.
It's not too hard to to work through the lines of text, justifying each one.
The multilineRender() function presented below does this. It first generates bitmaps of each line, and determines the maximum line-width. Once this width is known it becomes easy to left/right/centre justify by adjusting the x-coordinate.
Each of the bitmaps is then blitted to the pygame screen in turn. Obviously the y-coordinate is increased by the height of each bitmap as we go.
import sys
import pygame
from pygame.locals import *
mline_text="The Scroobious Pip went out one day\nWhen the grass was green, and the sky was grey.\nThen all the beasts in the world came round\nWhen the Scroobious Pip sat down on the ground.\n"
WIDTH = 600
HEIGHT= 500
WHITE = 255,255,255
BLUE = 0,0,200
###
### Draw a multi-line block of text to the screen at (x,y)
### With optional justification
###
def multilineRender(screen, text, x,y, the_font, colour=(128,128,128), justification="left"):
justification = justification[0].upper()
text = text.strip().replace('\r','').split('\n')
max_width = 0
text_bitmaps = []
# Convert all the text into bitmaps, calculate the justification width
for t in text:
text_bitmap = the_font.render(t, True, colour)
text_width = text_bitmap.get_width()
text_bitmaps.append((text_width, text_bitmap))
if (max_width < text_width):
max_width = text_width
# Paint all the text bitmaps to the screen with justification
for (width, bitmap) in text_bitmaps:
xpos = x
width_diff = max_width - width
if (justification == 'R'): # right-justify
xpos = x + width_diff
elif (justification == 'C'): # centre-justify
xpos = x + (width_diff // 2)
screen.blit(bitmap, (xpos, y) )
y += bitmap.get_height()
#start pygame, create a font for the text
pygame.init()
screen = pygame.display.set_mode((600,500))
pygame.font.init
myfont = pygame.font.Font(None,14)
screen.fill(BLUE)
# three copies of the same text, different justificaiton
multilineRender(screen, mline_text, 20, 20, myfont, WHITE)
multilineRender(screen, mline_text, 20,100, myfont, WHITE, justification="right")
multilineRender(screen, mline_text, 20,180, myfont, WHITE, justification="centre")
pygame.display.update()
while (True):
event = pygame.event.wait()
if event.type == QUIT:
pygame.quit()
sys.exit()

R the size of my graph is twice as big on linux than it is on windows

I have a strange problem with my stacked plots, which must be outputted as .png. I have R 3.1.3 on windows xp and on linux mint ( linux is my guest OS via virtual box , with my host windows xp). I have no other problem with my linux, besides the natural sluggishness of such a set-up. I must use linux because of the better management of the locales; windows renders all my characters from various alphabets all gibberish, despite the language pack installed.
The sizes of my graphs on linux (mint 17.1) are twice the ones on windows. Does this come from the fact that my linux is used via virtual box ?
I have no particular reason to install linux, that's why I have put it in a box. I have this little message when I log in on my linux through virtual box:
Can you tell me what sizes are the graphs on your system ?
the result in terms of sizes, see the GSC graphs
windowsGridnoGROBnoLOESS.png is 98 kB
windowsGridyesGROBnoLOESS.png is 679kB
windowsgscGROBnoLOESS.png is 332 kB
windowsGscnoGROBnoLOESS.png is 49 kB
windowsGscnoGROByesLOESS is 49 kB
windowsgscyesGROByesLOESS.png is 340 kB
linuxGridnoGROBnoLOESS is 104kB
linuxGridyesGROBnoLOESS is 729 kB
linuxgscGROBnoLOESS is 334 kB
linuxGscnoGROBnoLOESS is 48 kB
linuxGscnoGROByesLOESS is 115kB
linuxgscyesGROByesLOESS is 805 kB
especially once I incorporate the loess data, the size increases on linux but less on windows.
My personal graphs weight around 700KB on windows and nearly 3 MB on linux ! My graphs are closer to the graphs gsc since they have a long legend and are colored, with alpha layers and many many points with also the loess smoothings.
The basic graph can reproduce the phenomenon:
if you do not comment the first graph, you will need to download the data
here
I have put the arial font to avoid size discrepancies, but I think it is unnecessary. Feel free to comment the lines about the extrafonts and the line for the gsc plot theme.
require("ggplot2")
require("grid")
require("gridExtra")
require("extrafont")
# font_import() # import all your fonts
# fonts() #get a list of fonts
loadfonts(device = "win")
nmmaps<-read.csv("chicago-nmmaps.csv", as.is=T)
g<-ggplot(nmmaps, aes(date, temp, color=o3))+geom_point()
png(filename = "linuxGridnoGROBnoLOESS.png", width = 1920, height = 600, units = "px", pointsize = 11, bg = "white", res = 67.5)
g
dev.off()
png(filename = "linuxGridyesGROBnoLOESS.png", width = 1920, height = 4200, units = "px", pointsize = 11, bg = "white", res = 67.5)
grid.arrange(arrangeGrob(g,g,g,g,g,g,g,ncol=1, nrow=7))
dev.off()
gsc<- ggplot(aes(x = carat, y = price, color=cut), data = diamonds) + geom_point()+
theme_grey(base_family = "Arial") + theme(legend.background = element_rect(fill="grey95", colour=NA))
png(filename = "linuxGscnoGROBnoLOESS.png", width = 1920, height = 600, units = "px", pointsize = 11, bg = "white", res = 67.5)
gsc
dev.off()
png(filename = "linuxgscGROBnoLOESS.png", width = 1920, height = 4200, units = "px", pointsize = 11, bg = "white", res = 67.5)
grid.arrange(arrangeGrob(gsc,gsc,gsc,gsc,gsc,gsc,gsc,ncol=1, nrow=7))
dev.off()
gscloess<- ggplot(aes(x = carat, y = price, color=cut), data = diamonds) + geom_point()+
stat_smooth(method="loess", aes(group = 1), se=FALSE, span = 0.2, size=1.25, n=200, fullrange = T)+
theme_grey(base_family = "Arial") + theme(legend.background = element_rect(fill="grey95", colour=NA))
png(filename = "linuxGscnoGROByesLOESS.png", width = 1920, height = 600, units = "px", pointsize = 11, bg = "white", res = 67.5)
gscloess
dev.off()
png(filename = "linuxgscyesGROByesLOESS.png", width = 1920, height = 4200, units = "px", pointsize = 11, bg = "white", res = 67.5)
grid.arrange(arrangeGrob(gscloess,gscloess,gscloess,gscloess,gscloess,gscloess,gscloess,ncol=1, nrow=7))
dev.off()
I used optipng to reduce the size of the outputs from linux, but they remain higher than the ones on windows.
I also had to install xfonts-100-dpi and everything works, but the output is very ugly. but also very light.

Resources