I'm new to jetpack compose and i wanat to know if this is possible to achive with jetpack compose. Giving a background to text is very easy with compose but if you want to give indent to background according to text position i don't know where to start an achive this effect.
Text background with indent
I did that:
#Composable
fun IBgText(
text: String,
modifier: Modifier = Modifier,
iBgStrokeWidth: Float? = null,
iBgStrokeColor: Color = Color.DarkGray,
iBgVerticalPadding: Dp = 0.dp,
iBgHorizontalPadding: Dp = 0.dp,
iBgCornerRadius: Dp = 0.dp,
iBgColor: Color = Color.Gray,
color: Color = Color.Unspecified,
fontSize: TextUnit = TextUnit.Unspecified,
fontStyle: FontStyle? = null,
fontWeight: FontWeight? = null,
fontFamily: FontFamily? = null,
letterSpacing: TextUnit = TextUnit.Unspecified,
textDecoration: TextDecoration? = null,
textAlign: TextAlign? = null,
lineHeight: TextUnit = TextUnit.Unspecified,
overflow: TextOverflow = TextOverflow.Clip,
softWrap: Boolean = true,
maxLines: Int = Int.MAX_VALUE,
style: TextStyle = LocalTextStyle.current
) {
val vSpace = with(LocalDensity.current) { iBgVerticalPadding.toPx() }
val hSpace = with(LocalDensity.current) { iBgHorizontalPadding.toPx() }
val corner = with(LocalDensity.current) { iBgCornerRadius.toPx() }
var path by remember { mutableStateOf(Path()) }
fun computePath(layoutResult: TextLayoutResult): Path {
fun isInnerCorner(
lr: TextLayoutResult,
i: Int,
top: Boolean = false,
right: Boolean
): Boolean {
if (top && i == 0) return false
if (!top && i == lr.lineCount - 1) return false
if (top && right) return lr.getLineRight(i - 1) > lr.getLineRight(i)
if (!top && right) return lr.getLineRight(i + 1) > lr.getLineRight(i)
if (top && !right) return lr.getLineLeft(i - 1) < lr.getLineLeft(i)
return lr.getLineLeft(i + 1) < lr.getLineLeft(i)
}
val nbLines = layoutResult.lineCount
for (i in 0 until nbLines) {
var top = layoutResult.getLineTop(i)
var bottom = layoutResult.getLineBottom(i)
val right = layoutResult.getLineRight(i) + hSpace
val topInner = isInnerCorner(layoutResult, i, top = true, right = true)
val bottomInner = isInnerCorner(layoutResult, i, top = false, right = true)
if (topInner) top += vSpace else top -= vSpace
if (bottomInner) bottom -= vSpace else bottom += vSpace
path.apply {
if (i == 0) {
moveTo(right - corner, top)
} else {
if (topInner) {
lineTo(right + corner, top)
} else {
lineTo(right - corner, top)
}
}
quadraticBezierTo(right, top, right, top + corner)
lineTo(right, bottom - corner)
if (bottomInner) {
quadraticBezierTo(right, bottom, right + corner, bottom)
} else {
quadraticBezierTo(right, bottom, right - corner, bottom)
}
}
}
for (i in (nbLines - 1) downTo 0) {
var top = layoutResult.getLineTop(i)
var bottom = layoutResult.getLineBottom(i)
val left = layoutResult.getLineLeft(i) - hSpace
val topInner = isInnerCorner(layoutResult, i, top = true, right = false)
val bottomInner = isInnerCorner(layoutResult, i, top = false, right = false)
if (topInner) top += vSpace else top -= vSpace
if (bottomInner) bottom -= vSpace else bottom += vSpace
path.apply {
if (bottomInner) {
lineTo(left - corner, bottom)
} else {
lineTo(left + corner, bottom)
}
quadraticBezierTo(left, bottom, left, bottom - corner)
lineTo(left, top + corner)
if (topInner) {
quadraticBezierTo(left, top, left - corner, top)
} else {
quadraticBezierTo(left, top, left + corner, top)
}
}
}
path.close()
return path
}
Text(
text,
onTextLayout = { layoutResult ->
path = computePath(layoutResult = layoutResult)
},
modifier = modifier.drawBehind {
drawPath(path, style = Fill, color = iBgColor)
if (iBgStrokeWidth != null) {
drawPath(path, style = Stroke(width = iBgStrokeWidth), color = iBgStrokeColor)
}
},
color = color,
fontSize = fontSize,
fontStyle = fontStyle,
fontWeight = fontWeight,
fontFamily = fontFamily,
letterSpacing = letterSpacing,
textDecoration = textDecoration,
textAlign = textAlign,
lineHeight = lineHeight,
overflow = overflow,
softWrap = softWrap,
maxLines = maxLines,
style = style
)
}
Usage:
#Preview
#Composable
fun Preview() {
Column (modifier = Modifier.fillMaxSize().background(Color.Black)){
IBgText(
text = "test\ntest test\ntest\ntest test",
textAlign = TextAlign.Center,
modifier = Modifier.padding(top = 6.dp, start = 10.dp, end = 10.dp, bottom = 6.dp),
iBgColor = Color.Blue.copy(alpha = .4f),
iBgStrokeWidth = 3f,
iBgCornerRadius = 2.dp,
iBgHorizontalPadding = 5.dp,
iBgStrokeColor = Color.Red,
iBgVerticalPadding = 1.dp,
color = Color.White
)
IBgText(
text = "This is a sample\ntext",
textAlign = TextAlign.Center,
modifier = Modifier.padding(20.dp, bottom = 6.dp).rotate(-15f),
iBgColor = Color(0xFFFFFFFF),
iBgCornerRadius = 2.dp,
iBgHorizontalPadding = 8.dp,
iBgVerticalPadding = 5.dp
)
IBgText(
text = "line 1\n-- line 2 --",
textAlign = TextAlign.End,
modifier = Modifier.padding(10.dp)
)
}
}
Result:
It is not pretty, but i guess it does the job.
onTextLayout = { layoutResult -> gives the boundaries of each line.
left, top, bottom, right
Then you can make a path going through each line.
I did a loop from the top right corner (1st line end) to the bottom right corner (last line end)
Then another loop from the bottom left (last line start) to the top left (first line start).
Then I added some rounded corners to match the picture.
Ps: I started Kotlin and Jetpack compose this week and spend all my Sunday on your question 😅
I want to have slider widget to zoom in and out of a bokeh animation. The slider should zoom to a specific point in the figure (for example (100,123)) and have a maximum and minimum zoom level.
I am using curdoc() and bokeh server.
I was wondering how someone with more experience would do that.
thanks
This is a very simple example which you can further customise and improve. Position your point of interest in the middle e.g. (50, 50) and move the slider. This code works for Bokeh v1.0.4
import numpy as np
from bokeh.plotting import figure, show, curdoc
from bokeh.models import Slider, CustomJS, Range1d
from bokeh.layouts import column
slider_zoom = Slider(title = 'Zoom', start = -12, end = 8, value = 0, step = 1)
zoom_value = slider_zoom.value
x = np.linspace(-40, 40, 200)
y = x
p = figure(title = "Zoom Slider", plot_height = 500, plot_width = 600, y_range = Range1d(start = -40, end = 40), background_fill_color = '#efefef')
r = p.line(x, y, color = "red", line_width = 1.5, alpha = 0.8)
r = p.circle(x, y, color = "blue", line_width = 0.5, alpha = 0.8)
last_value = None
def update(attr, old, new):
global last_value
if last_value is not None:
if new > 0:
if new > last_value:
p.y_range.start = p.y_range.start + new
p.y_range.end = p.y_range.end - new
p.x_range.start = p.x_range.start + new
p.x_range.end = p.x_range.end - new
else:
p.y_range.start = p.y_range.start - new
p.y_range.end = p.y_range.end + new
p.x_range.start = p.x_range.start - new
p.x_range.end = p.x_range.end + new
elif new < 0:
if new < last_value:
p.y_range.start = p.y_range.start + new
p.y_range.end = p.y_range.end - new
p.x_range.start = p.x_range.start + new
p.x_range.end = p.x_range.end - new
else:
p.y_range.start = p.y_range.start - new
p.y_range.end = p.y_range.end + new
p.x_range.start = p.x_range.start - new
p.x_range.end = p.x_range.end + new
last_value = new
slider_zoom.on_change('value', update)
layout = column(p, slider_zoom)
curdoc().add_root(layout)
Result:
I am new to python and recently was able to generate a contourf animation. I know how to generate a colorbar, however I'm unsure as to how to implement a colorbar into the animation.
Also, is there a way to speed up the animation process?
My data is taken from an oscilloscope in a plane of measurement. Each location in the plane of measurement is stored as a file, where the file name is the location of measurement.
Below is my code.
from pylab import *
import matplotlib.animation as animation
# import pylab won't import animation
dr = 4;
dz = 4;
rStart = -72;
rEnd = 72;
zStart = -20;
zEnd = -236;
datatype = dtype('>d')
rspace = arange(rStart,rEnd+dr,dr)
zspace = arange(zStart,zEnd-dz,-dz)
tspace = 1000000 # number of samples
directory = 'D:\OscopeData\\'
data = zeros([len(zspace),len(rspace),tspace], dtype=datatype)
for j in range(0,len(zspace)):
for i in range(0,len(rspace)):
r = 'R' + str(rStart + dr(i))
z = 'Z' + str(zStart - dz(j))
datafile = directory + r + z + 'Ch1.dat'
data[j][i] = fromfile(datafile, dtype = datatype)
fig,ax = subplots()
textsize = 30
def animate(t):
ax.clear
ax.contourf(data[:,:,t],50)
title('Plot Title', fontsize = textsize + 6)
xlabel('R axis', fontsize = textsize)
ylabel('Z axis', fontsize = textsize)
anim = animation.FuncAnimation(fig, animate,50,blit=False)
I am fairly new to bokeh(using jupyter) and I was trying to create a simple line and scatter graph with a drop-down button where I could select a set of values for x-axis and y-axis and see them being updated in real time but for some reason for the graph does not get updated correctly this is a portion of my code:
weight= [23,45,11,40]
velocity= [12,65,32,15]
momentum = [12,78,22,40]
p = figure(plot_height=300,plot_width=500,title="Graph line of DATA")
p.title.text_font_style = "bold"
r = p.line(weight,velocity, color="red", line_width=3)
tab1=Panel(child=p, title="line")
p1 = figure(plot_height=300,plot_width=500,title="Graph line of DATA")
r1 = p1.circle(weight,velocity, size=10, color="red", alpha=0.5)
p1.title.text_font_style = "bold"
tab2=Panel(child=p1, title="Circle")
def updatex(Xaxis):
if Xaxis == "Weight":
func = weight
p.xaxis.axis_label = "pounds"
p1.xaxis.axis_label = "pounds"
elif Xaxis == "Velocity":
func = velocity
p.xaxis.axis_label = "m/s"
p1.xaxis.axis_label = "m/s"
elif Xaxis == "Momemtum":
func = momentum
p.xaxis.axis_label = "lb-sec"
p1.xaxis.axis_label = "lb-sec"
r.data_source.data['x'] = func
r1.data_source.data['x'] = func
push_notebook()
def updatey(Yaxis):
if Yaxis == "Weight":
func = weight
p.xaxis.axis_label = "pounds"
p1.xaxis.axis_label = "pounds"
elif Yaxis == "Velocity":
func = velocity
p.xaxis.axis_label = "m/s"
p1.xaxis.axis_label = "m/s"
elif Xaxis == "Momemtum":
func = momentum
p.xaxis.axis_label = "lb-sec"
p1.xaxis.axis_label = "lb-sec"
r.data_source.data['y'] = func
r1.data_source.data['y'] = func
push_notebook()
# the following snippet would be in the following cell below:
interact(updatex,Xaxis=["Weight", "Velocity", "Momemtum"])
interact(updatey,Yaxis=["Weight","Velocity","Momemtum"])
How do I plot excel bar chart from Matlab?
I'm able to plot line chart.
e = actxserver('excel.application');
eWs = e.Workbooks;
eW = eWs.Add;
eS = eW.ActiveSheet;
e.Visible = 1;
x=(0:2:100)';y=sin(x);
eS.Range('A1:B50').Value = [x y];
eCO = eS.ChartObjects.Add(100, 30, 400, 250);
eC = eCO.Chart;
eC.SeriesCollection.NewSeries;
eC.SeriesCollection(1).Value = eS.Range('B1:B50');
eC.SeriesCollection(1).XValue = eS.Range('A1:A50');
eCO.Chart.ChartType = 1;
eCO.Chart.ChartType = 65;
eCO.Chart.HasTitle = true;
eCO.Chart.ChartTitle.Text = 'This is the title text'; % view it again
eW.Close;e.Quit;delete(e);
Ok, I figured it out just after posting it.
We can get this by changing
eCO.Chart.ChartType = 65; to eCO.Chart.ChartType = 57;
e = actxserver('excel.application');
eWs = e.Workbooks;
eW = eWs.Add;
eS = eW.ActiveSheet;
e.Visible = 1;
x=(0:2:100)';y=sin(x);
eS.Range('A1:B50').Value = [x y];
eCO = eS.ChartObjects.Add(100, 30, 400, 250);
eC = eCO.Chart;
eC.SeriesCollection.NewSeries;
eC.SeriesCollection(1).Value = eS.Range('B1:B50');
eC.SeriesCollection(1).XValue = eS.Range('A1:A50');
eCO.Chart.ChartType = 1;
eCO.Chart.ChartType = 57;
eCO.Chart.HasTitle = true;
eCO.Chart.ChartTitle.Text = 'This is the title text'; % view it again
eW.Close;e.Quit;delete(e);
For further reference to other charts check this http://it.toolbox.com/wiki/index.php/EXCEL_Chart_Type_Enumeration