Python bokeh modify axis scale - python

How can I modify the y-axis scale at figures and at charts? I want something like this: my_figure.y_range.end = my_figure.y_range.end * 1.3
So I want a bit higher y-axis. Thank you!

Figure uses DataRange1d objects by default, which causes the range to automatically computed. But this happens on the browser, because it takes into account information like glyph extent that are only available at render time. The reason that my_figure.y_range.end * 1.3 does not work is because the "automatic" value of end is not known yet. It is only set automatically inside the browser. You can override the "automatic" behaviour of a DataRange by supplying start and end, but you have to give it an explicit, numeric value that you want, i.e.:
my_figure.y_range.end = 10
Alternatively, DataRange1d models have range_padding property that you can set, which controls the amount of "extra padding" added to the automatically computed bounds. It is described here:
http://docs.bokeh.org/en/latest/docs/reference/models/ranges.html#bokeh.models.ranges.DataRange1d.range_padding
This might accomplish what you want in a different way, but note that it affects both start and end.
Finally, if you'd just like to completely control the range, without having auto ranging at all, you can do this when you create the figure:
p = figure(..., x_range=(10, 20))
This will create a fixed Range1d for the x-axis with start=10 and end=20.

Related

How to find out what set_data expects

I'm trying to make an animation with matplotlib, in this case a 3D scatter plot. I'm hitting a problem that I absolutely always hit when I try to do this, which is that I don't know what arguments I should pass to set_data, and I don't know how to find out. In this case, it apparently expects two arguments, despite it being a 3d plot.
Since I've experienced related problems often, rather than asking about the specifics of the particular plot I'm trying to animate, I will ask the general question: given an element of a MatPlotLib plot, how can I determine what arguments its set_data method expects, either by interrogating it, or by knowing where it's documented?
From an example for an Animated 3D random walk from the MatPlotLib documentation:
def update_lines(num, dataLines, lines):
for line, data in zip(lines, dataLines):
# NOTE: there is no .set_data() for 3 dim data...
line.set_data(data[0:2, :num])
line.set_3d_properties(data[2, :num])
return lines
So as confusing as you discovered it is set_data by itself is not meant for 3D data, as well as according to the docs it accepts:
2D array (rows are x, y) or two 1D arrays
Looking more at this example we can see that the set_3d_properties has been used altogether.
This whole update_lines was set as a callback parameter for animation.FuncAnimation.
Usually to find the documentation you can either search it up online (e.g doc for set_data) or from a python prompt you can use the help function, which will show you the docstring of the object (can be used on a module/function/class etc) if it has any.
For example if you want to know what the datetime.datetime.now does (I dont have mathplotlib install to use it on it):
>>> import datetime
>>> help(datetime.datetime.now)
Help on built-in function now:
now(tz=None) method of builtins.type instance
Returns new datetime object representing current time local to tz.
tz
Timezone object.
If no tz is specified, uses local timezone.

create variable dynamically in a for loop

I know this question has been asked several times, I did find some post on this forum, but they don't seem to work, that's why I ask again.
Basically I have to create a number of a graph and the code is below
fig1 = go.Figure()
fig1.update_layout(showlegend = True, xaxis_title = "Time(s)")
and I would like to tidy it up using a for loop, therefore replacing the number with a variable, but doing something like below doesn't work
exec('"fig"+str(i) = go.Figure()')
I receive
SyntaxError: cant' assign to operator
How can I tidy this number of "same" code into a neat form, please?
*I also know that there is a danger using exec if this is not the way to go, what would be the better python way, please?
Edit:
This is my final working code, thanks for everyone's input
for i in range(5):
figures.update({f'fig{i}':go.Figure()})
eval('figures["fig'+str(i)+'"]').update_layout(showlegend = True, xaxis_title = "Time(s)")
In here, I can have control of the number of variable to be created (this code to be run. Also, putting it into the normal for loop form allows me to do more other things alone with the current figure. Lastly, the dictionary method allows a name to be linked to the figure so provides convenience
Why not try this:
figures = []
for i in range(loop):
figures.append(go.Figure())
#at this point you will now have n figures each of which you can reference
This way you still can find all of your plots if you know which order you made them in. Otherwise you could simply use a dict. I think its cleaner than making 10 diffrent variables.

Tkinter: Configure method for labels dynamically generated

I am trying to change the labels of my application with the configure method. The Labels are dynamically made in a for loop. Here is part of the code:
# create a list of reference for labels equal to zero
self.lbl_areas = []
for i in range(0, len(self.samples)): # number of labels
lbl=tk.IntVar()
lbl.set(0)
self.lbl_areas.append(tk.Label(self.win,textvariable=lbl))
# Place labels on the application using grid
for i,v in enumerate(self.lbl_areas):
v.grid(row=2+i,column=1,sticky=tk.W)
# Try to change the value
for i in range(0, len(self.samples)):
self.lbl_areas[i].configure(textvariable=lbl_val[i]) # other values
The default zero values are displayed but the configure method seems not to work. What do I do wrong?
There are two ways to update a label after it's been created. The first is to use a textvariable, where you update the variable and the label automatically picks up the change. The second is where you don't use a textvariable, and instead just change the label's text. You're trying to mix the two.
In my opinion, the best way is to not use a textvariable. It's an extra object you need to keep track of which provides no extra benefit (in this case, anyway).
In your case I would write the code like this:
for i in range(0, len(self.samples)): # number of labels
self.lbl_areas.append(tk.Label(self.win,text="0"))
...
for i in range(0, len(self.samples)):
self.lbl_areas[i].configure(text=lbl_val[i])
If you want to use the textvariable attribute, then you need to save a reference to the variable so that you can set it later:
for i in range(0, len(self.samples)): # number of labels
lbl=tk.IntVar()
lbl.set(0)
self.lbl_areas.append(tk.Label(self.win,textvariable=lbl))
self.lbl_vars.append(lbl)
...
for i in range(0, len(self.samples)):
self.lbl_vars[i].set(lbl_val[i])
Notice that in both cases, you must call a function (configure or set) to change the value. You either call it on the widget (widget.configure(...)) or on the variable (var.set(...)). Unless you're taking advantage of the special properties of a tkinter variable -- such as sharing the variable between two or more widgets, or using variable traces -- your code will be less complicated without the textvariable.

HTML like layouting

I'm trying to implement my own little flow-based layout engine. It should imitate the behavior of HTML layouting, but only the render-tree, not the DOM part. The base class for elements in the render-tree is the Node class. It has:
A link to the element in the DOM (for the ones that build a render-tree with that library)
A reference to it's parent (which is a ContainerNode instance or None, see later)
A reference to the layouting-options
X, Y, width and height (the position is computed in layout(), after the size has been computed in compute_size(). While the position is defined by the layout() method of the parent, the size is defined by the options reference, for instance).
It's methods are:
reflow() invoking compute_size() and layout()
compute_size() that is intended to compute the width and height of the node.
layout() which is intended to position the sub-nodes of the node, not the node itself.
paint() which is there to be overwritten by the user of the library.
The ContainerNode class is implementing the handling of sub-nodes. It provides a new method called add_node(), which adds the passed node to the containers children. The function also accepts a parameter force which defaults to False, because the container is allowed to deny the passed node, except force is set to True.
These two classes do not implement any layouting algorithm. My aim was to create different classes for the different types of layouts (In CSS, mainly defined by the display attribute). I did some tests with text-layouting last night and you can find my code from at pastebin.com (requires pygame). You can save it to a python script file and invoke it like this:
python text_test block -c -f "Georgia" -s 15
Note: The code is really really crappy. I appreciate comments on deep lying misconceptions.
The class InlineNodeRow from the code mentioned above actually represents my idea of how to implement the node that lays out similar to the display:inline attribute (in combination with the NodeBox).
Problem 1 - Margin & Padding for inline-text
Back to my current approach in the library: A single word from a text would also be represented as a single node (just like in the code above). But I noticed two things about margins and paddings in a <span> tag.
When margin is set, only horizontal margin is taken in account, the vertical margin is ignored.
The padding is overflowing the parent container and does not "move" the span node.
See http://jsfiddle.net/CeRkT/1/.
I see the problem here: When I want to compute the size of the InlineNodeBox, I ask a text-node for it's size and add it to the size of the node. But the text-nodes size is including it's margin and padding, which is not included in the HTML renderer's positioning. Therefore the following code would not be right:
def compute_size(self):
# Propagates the computation to the child-nodes.
super(InlineNodeBox, self).compute_size()
self.w = 0
self.h = 0
for node in self.nodes:
self.w += node.w
if self.h < node.h:
self.h = node.h
node.w would include the margin and padding. Next problem I see is, that I for laying out the text-nodes correctly, I wanted to split them into single TextNodes for each word, but the margin and padding would then be applied to all these nodes, while the margin and padding in HTML is to the <span> tag only.
I think my current idea of putting each word into a seperate node is not ideal. How to browsers structure their render-tree, or do you have a better idea?
Problem 2 - Word too long, put it into the next line.
The InlineNodeBox class currently only organizes a single line. In the code example above, I've created a new InlineNodeBox from within the NodeBox when the former refused to accept the node (which means it didn't fit in). I can not to this with my current approach, as I do not want to rebuild the render-tree all over again. When a node was accepted once, but exceeds the InlineNodeBox on the next reflow, how do I properly manage to put the word into the next line (assuming I keep the idea of the InlineNodeBox class only organizing a single line of nodes)?
I really hope this all makes sense. Feel free to ask if you do not understand my concept. I'm also very open to criticism and ideas for other concepts, links to resources, documentations, publications and alike.
Problem 2:
You can do it like HTML renderers do and render a multiline (e.g. check if the new word to be added exceeds the width and add a new line if it does). You can do it in your InlineNodeRow, by taking care of height too and wrapping words if they exceed the max width.
Problem 1:
If you do figure out problem 2 for text, then you can put in the offset (horizontal padding) only for the first line.
Although <span> doesn't take height into consideration, it does take line-height, so your calculation could be that the default height is the font height unless you have a line-height option available.
Mind you, if you have two or more successive InlineNodeRow representing spans, you'd need some smart logic to make the second one continue from where the first one ended :)
As a side note, From what I remember from Qt's rich text label, each set of words with the same rendering properties is considered to be a node, and its render function takes care of calculating all the stuff. Your approach is a bit more granular and its only disadvantage from what I see is that you can't split words.
HTH,
May have found solution to problem 1 in the box model documentation (you may want to check out the documentation about clearance and the one for overflow as well for problem 2).
"margins of absolutely positioned boxes do not collapse."
You can see this jsfiddle for an example.

Force matrix_world to be recalculated in Blender

I'm designing an add-on for blender, that changes the location of certain vertices of an object. Every object in blender has a matrix_world atribute, that holds a matrix that transposes the coordinates of the vertices from the object to the world frame.
print(object.matrix_world) # unit matrix (as expected)
object.location += mathutils.Vector((5,0,0))
object.rotation_quaternion *= mathutils.Quaternion((0.0, 1.0, 0.0), math.radians(45))
print(object.matrix_world) # Also unit matrix!?!
The above snippet shows that after the translation, you still have the same matrix_world. How can I force blender to recalculate the matrix_world?
You should call Scene.update after changing those values, otherwise Blender won't recalculate matrix_world until it's needed [somewhere else]. The reason, according to the "Gotcha's" section in the API docs, is that this re-calc is an expensive operation, so it's not done right away:
Sometimes you want to modify values from python and immediately access the updated values, eg:
Once changing the objects bpy.types.Object.location you may want to access its transformation right after from bpy.types.Object.matrix_world, but this doesn’t work as you might expect.
Consider the calculations that might go into working out the objects final transformation, this includes:
animation function curves.
drivers and their pythons expressions.
constraints
parent objects and all of their f-curves, constraints etc.
To avoid expensive recalculations every time a property is modified, Blender defers making the actual calculations until they are needed.
However, while the script runs you may want to access the updated values.
This can be done by calling bpy.types.Scene.update after modifying values which recalculates all data that is tagged to be updated.
Calls to bpy.context.scene.update() can become expensive when called within a loop.
If your objects have no complex constraints (e.g. plain or parented), the following can be used to recompute the world matrix after changing object's .location, .rotation_euler\quaternion, or .scale.
def update_matrices(obj):
if obj.parent is None:
obj.matrix_world = obj.matrix_basis
else:
obj.matrix_world = obj.parent.matrix_world * \
obj.matrix_parent_inverse * \
obj.matrix_basis
Some notes:
Immediately after setting object location/rotation/scale the object's matrix_basis is updated
But matrix_local (when parented) and matrix_world are only updated during scene.update()
When matrix_world is manually recomputed (using the code above), matrix_local is recomputed as well
If the object is parented, then its world matrix depends on the parent's world matrix as well as the parent's inverse matrix at the time of creation of the parenting relationship.
I needed to do this too but needed this value to be updated whilst I imported a large scene with tens of thousands of objects.
Calling 'scene.update()' became exponentially slower, so I needed to find a way to do this without calling that function.
This is what I came up with:
def BuildScaleMatrix(s):
return Matrix.Scale(s[0],4,(1,0,0)) * Matrix.Scale(s[1],4,(0,1,0)) * Matrix.Scale(s[2],4,(0,0,1))
def BuildRotationMatrixXYZ(r):
return Matrix.Rotation(r[2],4,'Z') * Matrix.Rotation(r[1],4,'Y') * Matrix.Rotation(r[0],4,'X')
def BuildMatrix(t,r,s):
return Matrix.Translation(t) * BuildRotationMatrixXYZ(r) * BuildScaleMatrix(s)
def UpdateObjectTransform(ob):
ob.matrix_world = BuildMatrix(ob.location, ob.rotation_euler, ob.scale)
This isn't most efficient way to build a matrix (if you know of a better way in blender, please add) and this only works for XYZ order transforms but this avoids exponential slow downs when dealing with large data sets.
Accessing Object.matrix_world is causing it to "freeze" even though you don't do anything to it, eg:
m = C.active_object.matrix_world
causes the matrix to be stuck. Whenever you want to access the matrix use
Object.matrix_world.copy()
only if you want to write the matrix, use
C.active_object.matrix_world = m

Categories