How to draw a number axis with arrow - manim

I need to draw a horizontal axis to decribe number, currently there is a NumberLine which can work, however there is no arrow to indicate the positive direction.
Is there built-in object to do that? or manually create such class with code?

If you have doubts about how an object works, you can look for it in the source code manimlib/mobject/
In your case it is in number_line.py, the code is not difficult to understand and thus you avoid asking.
class NumberLineExample(Scene):
def construct(self):
nl=NumberLine(x_min=-2,
x_max=2,
include_numbers=True,
include_tip=True,
label_direction=UP
)
self.add(nl)
If you see the source code you find all options:
class NumberLine(Line):
CONFIG = {
"color": LIGHT_GREY,
"x_min": -FRAME_X_RADIUS,
"x_max": FRAME_X_RADIUS,
"unit_size": 1,
"include_ticks": True,
"tick_size": 0.1,
"tick_frequency": 1,
# Defaults to value near x_min s.t. 0 is a tick
# TODO, rename this
"leftmost_tick": None,
# Change name
"numbers_with_elongated_ticks": [0],
"include_numbers": False,
"numbers_to_show": None,
"longer_tick_multiple": 2,
"number_at_center": 0,
"number_scale_val": 0.75,
"label_direction": DOWN,
"line_to_number_buff": MED_SMALL_BUFF,
"include_tip": False,
"tip_width": 0.25,
"tip_height": 0.25,
"decimal_number_config": {
"num_decimal_places": 0,
},
"exclude_zero_from_default_numbers": False,
}

Related

Docking Ranges and Conditions

I have a part that is a rectangle of 1200mm x 400mm x 400mm, this part can be divided into 3 equal sizes, within these equal sizes I need to Dock different parts. I have set a Docking Range for every 400mm (which is fine) I have 3 style of parts that need to Dock into the 400mm gaps, so I have set on the main 1200 part 3 KEYS (bridgePos1InfillType, bridgePos2InfillType, bridgePos3InfillType) and currently when I dock a part inside these I set the TYPE that was docked...
"mask": "cubby",
"position": "{0, 0, 40}",
"stepEnd": "{800, 0, 0}",
"rotation": "{0, 0, 0}",
"condition": "(((configID=='v2')||(configLadderID=='v2'))&&(cubeHeight==400))",
"maxConnections": 1,
"stepX": 400,
"stepY": 0,
"stepZ": 0,
"assignmentScripts": {
"onDock": "index = connection.index;
if(index=='0'){bridgePos1InfillType='cubby'};
if(index=='1'){bridgePos2InfillType='cubby'};
if(index=='2'){bridgePos3InfillType='cubby'}",
"onUpdate" : "",
"onUnDock": "index = connection.index;
if(index=='0'){bridgePos1InfillType='blank'};
if(index=='1'){bridgePos2InfillType='blank'};
if(index=='2'){bridgePos3InfillType='blank'}"
}
But what I want to happen is when I then try to docking a different part (using Docking Range) it should not let me as the InFillType is not BLANK
this is my next part to dock but how do I check to see if the Docking Range Position in already taken or that the bridgePos1InFillType is not BLANK...
{
"mask": "cupboard400x400",
"position": "{0, 0, 40}",
"stepEnd": "{800, 0, 0}",
"rotation": "{0, 0, 0}",
"condition": "index = connection.index;
(((configID=='v2')||(configLadderID=='v2'))&&(cubeHeight==400))",
"maxConnections": 1,
"stepX": 400,
"stepY": 0,
"stepZ": 0
},
You can utilize internal value called condition in all condition statements, like this:
"condition": "
/* you probably want to check if you're in preview, otherwise you could delete it right after docking, if the condition result becomes false */
if (connection.isPreview) {
/* then checking against which internal var to check this */
if (connection.index == 1) { condition = bridgePos1InfillType == 'blank'; }
...
/* then you can do further checks like */
condition = condition && (!maximumLoadExceeded);
} else {
/* if it is already there, just don't worry & keep it */
condition = true;
}
"
There is connection.index or connection.position to check the current position in the range's array. For 2D ranges, I recommend approach of computing the indices from connection.position. For 1D range, connection.index works just fine. See https://docs.roomle.com/scripting/resources/200_80_dockingbasics.html#docking-ranges and https://docs.roomle.com/scripting/resources/200_140_advanceddockinglogic.html#docking-ranges
I also see that an array would be good for you. If you worry only about whether there is something already docked, you could do an array of booleans occupied = [0,0,0] and then access the values using get(self.occupied, connection.index) in condition and use the set function in assignment scripts. If you need to also know what is occupied, RoomleScript unfortunately only supports arrays of numbers. A possible solution would be to have a 1:1 constant numeric identifier for every type.
See also https://docs.roomle.com/scripting/resources/200_40_roomlescript.html#arrays

Highstock step multiple data points on same x axis

When the highstock chart data set has multiple points on the same axis ex:
data: [[0,0], [0, 100], [1, 100], [1,200], [4, 100], [4, 200]]
the point doesn't always choose the highest number by default. It looks like it randomly selects one of the numbers on the same axis.
Here's my fiddler example: http://jsfiddle.net/ceo1y97m/
As you can see when you hover over the different points, it's not always displaying the highest point's Y value. How do I get this to show only the highest point's value?
Edit: Here is the reason that I have multiple x values that are the same:
Let's say the line represents the amount of money you deposit into an account over time. In the line's legend I want to display the amount you've deposited over the period that you're viewing. This would be the furthest point right's Y value minus the furthest point left's Y value. If I don't include the duplicate Y values, this calculation is incorrect.
See updated fiddler to show this error on the legend value (zoom in and out to change the legend values): https://jsfiddle.net/LS384/822/
The two data sets look identical, but the legend values are different, because both points on the same axis aren't displayed.
I'm not sure that this is how the step chart was intended to be used, you should have just 1 value per axis point.
What you could do is filter your data to just keep the highest value for each point
data: [[0,0], [0, 100], [1, 100], [1,200], [4, 100], [4, 200]]
for (var i in data) {
if (filteredData[data[i][0]] == undefined) {
filteredData[data[i][0]] = data[i]
} else {
if (filteredData[data[i][0]][1] < data[i][1]) {
filteredData[data[i][0]] = data[i];
}
}
}
here is your edited filter with the chart looking the same and you desired behaviour http://jsfiddle.net/ceo1y97m/4/
Edit:
I made a workaround, i hid the unfiltered data, used the filtered data for display and gave it the same color as the unfiltered one, and in the function that calculates the difference i use the unfiltered data(ch.series[0].data])
Here is the fiddle with your expected behaviour https://jsfiddle.net/LS384/826/
I would process the data, so you have one point per x value with additional information - multiple values. I treat { x, y } as the information about how the point should be visualised plus add the array with all additional values which allow to make the proper calculations.
This:
[
[0, 0],
[0, 100],
[1, 100],
[1, 200],
[1, 300],
becomes this:
[{
x: 0,
y: 100,
values: [0, 100]
}, {
x: 1,
y: 300,
values: [100, 200, 300]
}]
With points defined as the above, you can access the values via point.options.values and calculate the difference.
example: http://jsfiddle.net/jqdh79vv/

Highcharts linearGradient fill with fixed upper bound

I'm looking to achieve an effect similar to that in this example.
However, the above example uses a gradient that is relative to the visible plot. So the 0 stop color is used at the peak of the visible plot (whatever the actual value of the peak), and the 1 stop color is used at the base.
Say I have data that can range from 0 to 100 (e.g. a percentage). I want to be able to specify that "dark" is always used for a value of 100, while "light" is always used for a value of 0.
So, if my visible data only ranges from 0 to 20, then this is all filled with a light-ish gradient colour (at the lower end of the gradient spectrum)... I don't want it to be filled from light to fully dark.
Any way to achieve this?
To achieve such gradient, you need to do a few things.
Gradient units should be switched to userSpaceOnUse.
x1, y1, x2, y2 should point to the points where the plot area starts and ends.
You do not know what would be the plot area, so you have to set the gradient on load event.
function() {
this.series[0].update({
fillColor: {
linearGradient: [0, 0, 0, this.plotHeight]
}
});
}
example: http://jsfiddle.net/qhuee8uf/1/
Now, the gradient has fixed x/y attributes, what means that the gradient will not be responsive. To have a gradient which will work with a resizing chart, you should recalculate gradient on redraw event.
Also, I have found that updating gradient in the series does not update the gradient but creates a new one - which might be not be the best behaviour to have.
Instead, you can modify the gradient attributes directly
function adjustGradient() {
document.getElementsByTagName('linearGradient')[0].setAttributeNS(null, 'y2', this.plotHeight);
}
chart: {
events: {
load: adjustGradient,
redraw: adjustGradient
}
},
example: http://jsfiddle.net/qhuee8uf/

Line chart with fix X axis label like healthkit graph in iOS

hello I want to create line chart similar to healthkit. For example i have on X axis (Jul 14, 15, 16, 17), Y axis (0, 50, 100) and data set in (x,y) format is ((jul 15, 30),(jul 17, 80))
I try following libraries
https://github.com/Boris-Em/BEMSimpleLineGraph/tree/master/Sample%20Project/SimpleLineChart
https://github.com/core-plot/core-plot
but all populate x axis based on data set. i.e all library only take parameter for data set based on that x axis and y axis labels are populated. Can you please suggest any other library through which I can achieve similar as explain above line chart. Thanks in advance.
Finally i solved my problem using
https://github.com/Boris-Em/BEMSimpleLineGraph/tree/master/Sample%20Project/SimpleLineChart
when there is no value i put (jul 15, BEMNullGraphValue).
Even this you could do it in your existing graph
Consider below example.
- {[0,5],[1,5],[3,5],[4,5]}
See there is no value for 2, so line chart will draw 0-5 to 1-5 then gap then 3-5 to 4-5.
I hope now you could figure out.
Still if you wish then get below graph library.
Do it with https://github.com/danielgindi/Charts
There are many properties like clip, scale, min, max etc for line chart.
Using though properties you could achieve.
https://github.com/danielgindi/Charts/issues/533
Edited answer
After doing some work around, i found the way.
Download sample code
let months = ["July 14", "15", "16", "17", "18", "19", "20"]
let unitsSold = [0.0, 0.0, 0.0, 100.0, 25.0, 50.0, 75.0]
for i in 0..<dataPoints.count {
if !values[i].isZero {
let dataEntry = ChartDataEntry(value: Double(values[i]), xIndex: i)
dataEntries.append(dataEntry)
}
}
Refer attached screen shot
In PNChart create one array of indexes which you want to skip the value. Put condition drawdot funtion on start of for loop of data array if array contain index value then continue.

Apply merge layers on multiple images without losing layers

My problem:
I want to make a lot of images that differ only in three text layers. I have already figured out, how to make the text changes with the Python-Fu Console. My next step is to put this text change code into a loop and add a png.file-save-png(...) to save the picture. In order to save as a PNG I have to merge all my layers (for each image), which is no problem with single_layer = pdb.gimp-image-merge-visible-layers(image,0). In order to keep working from here, I would need to to an undo, to get my old layers back.
Do I need to apply an UNDO Operation in GIMP from a script?
I couldn't find any hint on this feature. Maybe anyone knows how to do this, or has a workaround.
After a night of sleep, I figured out a workaround:
I reopened the base image file for each card in the loop, where all layers and text layers stayed intact. That prevented me from needing the undo.
By the way, here is my script for creating 4 * 13 playing cards (from ones own base_card.xcf):
basefile = "/home/[...]/base_card.xcf"
basesave = "/home/[...]/"
color_blue = [ (32.0 /255.0, 74.0/255.0,135.0/255.0,1.0),
(52.0 /255.0,101.0/255.0,164.0/255.0,1.0)]
color_red = [ (164.0/255.0, 0.0/255.0, 0.0/255.0,1.0),
(204.0/255.0, 0.0/255.0, 0.0/255.0,1.0)]
color_yellow = [ (196.0/255.0,160.0/255.0, 0.0/255.0,1.0),
(237.0/255.0,212.0/255.0, 0.0/255.0,1.0)]
color_green = [ ( 78.0/255.0,154.0/255.0, 6.0/255.0,1.0),
(115.0/255.0,210.0/255.0, 22.0/255.0,1.0)]
def createCard(color_list, color_name, number):
pdb.gimp_context_set_foreground(color_list[1])
image = pdb.gimp_file_load(basefile, basefile)
textlayers = image.layers[0:3]
for layer in textlayers:
pdb.gimp_text_layer_set_text(layer, number)
pdb.gimp_text_layer_set_color(layer, color_list[0])
layer = image.layers[3]
pdb.gimp_edit_bucket_fill(layer, 0, 0, 100, 0, 0, 30, 30)
layer = pdb.gimp_image_merge_visible_layers(image, 0)
savename = "%s%s_%s.png" % (basesave, color_name, number)
pdb.file_png_save(image, layer, savename, savename, 0, 0, 0, 0, 0, 0, 0)
image = None
for c in range(1,14):
createCard(color_blue, "BLUE", c)
for c in range(1,14):
createCard(color_yellow, "YELLOW", c)
for c in range(1,14):
createCard(color_red, "RED", c)
for c in range(1,14):
createCard(color_green, "GREEN", c)

Resources