I want to paint variables of MathTex element in different colors, but Manim seems to have problems with comlicated Latex expressions.
Here is my scene.
from manim import *
config.frame_width = 260
class Find_Path(Scene):
def construct(self):
obj = MathTex(r"minimize \quad \sum_{start}^{end}\frac{d_{i,i+1}}{v_{i,i+1}}",
font_size=1000, substrings_to_isolate="d" and "v")
obj.set_color_by_tex("d", YELLOW)
obj.set_color_by_tex("start", GREEN)
obj.set_color_by_tex("end", GREEN)
obj.set_color_by_tex("v", RED)
self.play(Write(obj))
self.wait(3)
Here is the result.
Specifically, I want to color d_{i,i+1} in YELLOW, v_{i,i+1} in RED, start and end in GREEN.
Any advice? Frankly, I do not want to create several MathTex object in different colors and then arrange them.
Manim does a bunch of tex rewriting under the covers, and it seems that over is preferred to frac because of that rewriting.
I was able to apply the colors that you wanted (although I suspect you didn't want the sum symbol colored) with:
from manim import *
class Find_Path(Scene):
def construct(self):
obj1 = MathTex(r"\text{minimize}", r"\quad \sum_{\text{start}}^{\text{end}}")
obj2 = MathTex(r"d_{i,i+1}", r"\over", r"v_{i,i+1}")
obj1.set_color_by_tex("start", GREEN)
obj1.set_color_by_tex("end", GREEN)
obj2.move_to(obj1, RIGHT)
obj2.shift(1.5 * RIGHT)
obj2[0].set_color(YELLOW)
obj2[2].set_color(RED)
self.play(AnimationGroup(Write(obj1), Write(obj2)))
self.wait(3)
but I had to resort to separate objects. Worse still, I aligned them by hand with a fudge factor.
Late answer, but I encountered a similar issue and ended up here before finding the relevant section in the documentation.
Relevant section in documentation: Using index_labels to work with complicated strings
An example with your special case:
from manim import *
config.frame_width = 8
config.frame_size = (1300, 1000)
class FindPath(Scene):
def construct(self):
# You can split the string in parts
minimize = r"minimize \quad "
summ = r"\sum_{start}^{end}"
frac = r"\frac{d_{i,i+1}}{v_{i,i+1}}"
tex = MathTex(minimize, summ, frac).shift(2 * UP)
# Observe first level labels
tex_ = tex.copy().next_to(tex, DOWN)
self.add(index_labels(tex_, color=YELLOW))
# Observe second level labels
tex__ = tex_.copy().next_to(tex_, DOWN)
for part in tex__:
self.add(index_labels(part, color=YELLOW))
# Finally you can color accordingly
tex[1][0:3].set_fill(color=GREEN)
tex[1][4:9].set_fill(color=GREEN)
tex[2][0:6].set_fill(color=YELLOW)
tex[2][7:13].set_fill(color=RED)
self.add(tex, tex_, tex__)
Related
i'm working on a program that should figure out the dimensions of individual pieces in kitchen cabinet modules, so you only set: height, depth, width of the material(18mm), and then you select modules from a list and after setting the dimensions of each you should be presented with a list of pieces and their dimensions.
Since all of this is somewhat standardized individual pieces's dimensions are figured out by simple math, but each consists of it's own set of operations, which should be ran once and display the results in the interface(eventually i'll figure out how to write it to an excel compatible format)
as you can see here it can get to be complex, i can work it out over time no problem, but right now i'm not sure PYGUI is what i need.
import PySimpleGUI as sg
layout1 = [[sg.Text('Altura', size=(10,1)),sg.Input('',key='Alt')], #Height
[sg.Text('Densidad Placa', size=(10,1)),sg.Input('',key='Placa')],# Material's density
[sg.Text('Profundidad', size=(10,1)),sg.Input('',key='Prof')]] #Depth
layout2 = [[sg.Text('Ancho Modulo', size=(10,1)),sg.Input('',key='WM')], #Module's width
[sg.Text('lateral', size=(10,1)),sg.Text('',key='Lat'),sg.Text('x'),sg.Text('',key='Prof2')], #side pieces
[sg.Text('Piso', size=(10,1)),sg.Text('',key='WM2'),sg.Text('x'),sg.Text('',key='Prof2')], # bottom piece
[sg.Button('Go')]]
#Define Layout with Tabs
tabgrp = [[sg.TabGroup([[sg.Tab('1', layout1),
sg.Tab('2', layout2)]])]]
window =sg.Window("Tabs",tabgrp)
#Read values entered by user
while True:
event,values=window.read()
if event in (sg.WINDOW_CLOSED, 'Close'):
break
elif event == 'Go':
anc = values['WM']
altura = values['Alt']
placa = values['Placa']
prof = values['Prof']
try:
v = int(anc) #width
w = int(prof)#depth
x = int(altura)#height
y = int (placa)# Material's density
altlat = str(x - y) #height of side pieces
prof2 = int(w - y) #depth of pieces,(total depth incluiding the door)
ancm = int(v) #width
except ValueError:
altlat = "error"
prof2 = "error"
ancm = "error"
window['Lat'].update(value=altlat)
window['Prof2'].update(value=prof2)
window['WM2'].update(value=ancm)
window.refresh
#access all the values and if selected add them to a string
window.close()
i figured i use functions for every set of operations and call them as i need them, but keys can't be reused and every tutorial i've seen points towards them, and other implementations i tried failed,. i've been using python since last night, so i'm not sure how many options i have, nor how limited my options will be with PYGUI's toolset.
I think what you are asking is, how can I make a function that will take the values and run an operation on them? This seems to be more of a general python question than one about pyGUI, but here is a quick answer.
def calc_side_panel_height(altura, placa):
x = int(altura)#height
y = int (placa)# Material's density
return (x - y) #height of side pieces
try {
height_of_side = calc_side_panel_height(altura, place)
# use height here.
altlat = str(height_of_side)
}
does that start to make sense? You would call functions and in those functions do the calculations, so you don't have to rewrite the code.
more info: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Functions
Let me know if I'm confused!
Goal
I want to plot a large number of cubes (arranged in a 3D grid) with different colors and opacities.
Current State and question
I have come up with a solution using vispy, but the performance is very poor - drawing takes very long and the window is very unresponsive. Also, there seem to be some glitches in the visualization, but I could live with those.
Is there a more efficient/elegant way to implement that? I am open to using other packages (I have tried open3d but found it difficult to specify colors and opacities - the documentation is not very verbose). However, I need to use python.
What I did so far
The first problem I had to solve with vispy was that I was unable to create cubes at custom positions. I therefore wrote a subclass that can do that:
import vispy.visuals
from vispy.geometry import create_box
class PositionedCubeVisual(vispy.visuals.BoxVisual):
def __init__(self, size=1, position=(0, 0, 0), width_segments=1,
height_segments=1, depth_segments=1, planes=None,
vertex_colors=None, face_colors=None,
color=(0.5, 0.5, 1, 1), edge_color=None, **kwargs):
vertices, filled_indices, outline_indices = create_box(
size, size, size, width_segments, height_segments,
depth_segments, planes)
for column, pos in zip(vertices['position'].T, position):
column += pos
self._mesh = vispy.visuals.MeshVisual(vertices['position'], filled_indices,
vertex_colors, face_colors, color)
if edge_color:
self._border = vispy.visuals.MeshVisual(vertices['position'], outline_indices,
color=edge_color, mode='lines')
else:
self._border = vispy.visuals.MeshVisual()
vispy.visuals.CompoundVisual.__init__(self, [self._mesh, self._border], **kwargs)
self.mesh.set_gl_state(polygon_offset_fill=True,
polygon_offset=(1, 1), depth_test=True)
PositionedCube = vispy.scene.visuals.create_visual_node(PositionedCubeVisual)
I then plot the cubes as follows:
import numpy as np
import vispy.scene
def plot_grid_cubes(x, y, z, c=None, size=1, alpha=0.1, edge_color="black",
cmap="viridis", bgcolor="#FFFFFF"):
canvas = vispy.scene.SceneCanvas(keys='interactive', show=True)
view = canvas.central_widget.add_view()
view.bgcolor = bgcolor
view.camera = 'turntable'
c = get_color_array(c, alpha, min(len(x), len(y), len(z)), cmap)
for xx, yy, zz, cc in zip(x, y, z, c):
cube = PositionedCube(size, (xx, yy, zz), color=cc, edge_color=edge_color, parent=view.scene)
canvas.app.run()
def get_color_array(c, alpha, size, cmap):
if c is not None:
cmap = cm.get_cmap(cmap)
if hasattr(c, "__iter__"):
c = np.array(c, copy=True, dtype=float)
c -= c.min()
c *= 255/c.max()
return cmap(c.astype(int), alpha)
else:
color = np.ones((size, 4))
color[:, 3] = alpha
return color
This can then be applied as follows:
plot_grid_cubes([0, 1], [0, 1], [0, 1], c=[0.3, 0.5], alpha=[0.3, 0.8])
The example above works great, but it becomes poor if I plot thousands of cubes.
Regarding performance on vispy, you may want to read this:
Each Visual object in VisPy is an OpenGL Program consisting of at least a vertex shader and a fragment shader (see Modern OpenGL). In general, except for some very specific cases, OpenGL Programs can only be executed one at a time by a single OpenGL context. This means that in your VisPy visualization each Visual object you tell VisPy to draw will extend how long each update (draw) takes. When frames per second (FPS) or responsiveness are a concern, this means each Visual you add reduces the performance of your visualization.
While VisPy is constantly striving to improve performance, there are things that you can do in the mean time (depending on your particular case). The most important change that you can make is to lower the number of Visual objects you have. For a lot of Visuals it is possible to combine them into one by putting a little extra work into the data you provide them. For example, instead of creating 10 separate LineVisuals, create 1 LineVisual that draws 10 lines. While this is a simple example, the same concept applies to other types of Visuals in VisPy and more complex use cases. As a last resort for the most complex cases, a custom Visual (custom shader code) may be necessary. Before writing a custom Visual, check with VisPy maintainers by asking a question on gitter or creating a question as a GitHub issue.
Now for the BoxVisual this is a little difficult because as far as I can tell this "convenience" class doesn't allow you to make many boxes with a single BoxVisual instance. Since you are already comfortable making a Visual subclass I would recommend making the MeshVisuals yourself and providing the vertices for each box as one single position array.
As for not being able to specify position, this won't apply to your custom Visual class that will use the all-in-one array since you'll be providing each position at the beginning, but I thought I should still describe it. It is unfortunate that the BoxVisual is trying to be so convenient that it isn't helpful in this case since other Visuals allow you to pass your vertex positions on creation. In other cases or when you only want to make small modifications, typically what is done in VisPy is to use one or more "transforms" added to the Visual to shift (transform) the positions passed to the Visual. For example:
from vispy.visuals.transforms import STTransform
cube = ... create a cube visual ...
cube.transform = STTransform(scale=(1.0, 1.0, 1.0), translate=(0.0, 0.0, 0.0))
where you change the scale and translate values as needed to effect (X, Y, Z) coordinate values. After this, if you modify the cube.transform.translate = (new_x, new_y, new_z) property (or .scale or use another transform class) directly this has the benefit of only modifying that property on the GPU and not needing to recompute and resend the vertex positions (better performance).
I have a mayavi object with a number of vertices and I would like to set RGB or RGBA values directly for these vertices, rather than restrict myself to a single colormap with scalars. How can this be accomplished?
As far as I am aware, there is no documentation for doing this, but I have found a way to do it with only a minimum amount of hacking around. Here is a minimal example, which might require a little tinkering for different kinds of sources:
from tvtk.api import tvtk; from mayavi import mlab; import numpy as np
x,y,z=np.random.random((3,nr_points)) #some data
colors=np.random.randint(256,size=(100,3)) #some RGB or RGBA colors
pts=mlab.points3d(x,y,z)
sc=tvtk.UnsignedCharArray()
sc.from_array(colors)
pts.mlab_source.dataset.point_data.scalars=sc
pts.mlab_source.dataset.modified()
It also looks like sometimes you have to ensure that the mapper points to the right thing. This is not necessary for the above example, but it may be for other sources
pts.actor.mapper.input=pts.mlab_source.dataset
At some point the mayavi API should be fixed better so that there is an API exposed to just do this for all the pipeline functions, but that turns out to be a rather complicated and sweeping set of changes which I don't currently have time to finish.
Edit:
User eqzx posted an answer to another question (Specify absolute colour for 3D points in MayaVi) which may be simpler, especially for certain source types that are hard to get to work with tvtk.UnsignedCharArray.
His idea is to create a LUT spanning the entire range of 256x256x256 RGB values. Note that this LUT therefore has 16,777,216 entries. Which, if you wanted to use it in many vtk objects, may waste quite a lot of memory if you are not careful.
#create direct grid as 256**3 x 4 array
def create_8bit_rgb_lut():
xl = numpy.mgrid[0:256, 0:256, 0:256]
lut = numpy.vstack((xl[0].reshape(1, 256**3),
xl[1].reshape(1, 256**3),
xl[2].reshape(1, 256**3),
255 * numpy.ones((1, 256**3)))).T
return lut.astype('int32')
# indexing function to above grid
def rgb_2_scalar_idx(r, g, b):
return 256**2 *r + 256 * g + b
#N x 3 colors
colors = numpy.array([_.color for _ in points])
#N scalars
scalars = numpy.zeros((colors.shape[0],))
for (kp_idx, kp_c) in enumerate(colors):
scalars[kp_idx] = rgb_2_scalar_idx(kp_c[0], kp_c[1], kp_c[2])
rgb_lut = create_8bit_rgb_lut()
points_mlab = mayavi.mlab.points3d(x, y, z
keypoint_scalars,
mode = 'point')
#magic to modify lookup table
points_mlab.module_manager.scalar_lut_manager.lut._vtk_obj.SetTableRange(0, rgb_lut.shape[0])
points_mlab.module_manager.scalar_lut_manager.lut.number_of_colors = rgb_lut.shape[0]
points_mlab.module_manager.scalar_lut_manager.lut.table = rgb_lut
I wrote a program for a class using recursion to mimic certain kinds of simple branching structures like trees. I thought my code was great until I showed my professor. He told my code was too complicated and said I would need to simplify it. Besides spacing them out, I'm not sure what else I could do. Any tips? (I'm a beginner so go easy on me.) This program creates multiple trees with varying thickness, number of branch and at different coordinates.
import random
import turtle
##I'm using a python module called turtle to visualize results
p1 = turtle.Pen()
##Creates a pen
p1.tracer(True)
## Shows pen drawing
p1.up()
p1.left(90)
d=random.randint(0,2)
## Varying thickness of branch
length=150
##Length of branches
contract=random.uniform(.5,1)
## Varying degree of contraction
branch=random.randint(5,8)
## Varying amount of branches
first=random.randint(30,70)
## Varying first degree of branch
next=random.randint(1,30)
## Varying degree between each branches
number1=random.randint(10,20)
number2=random.randint(-100,100)
number3=random.randint(-100,100)
# Range of numbers used for coordinates
def drawFern1(pen, depth, length, contractBy, branches, firstBranchAngle, nextBranchAngle):
if depth > 0:
#Pen's Position and heading
heading = pen.heading()
position = pen.position()
pen.width(depth)
pen.forward(length)
pen.left(firstBranchAngle)
for i in range(branches):
drawFern1(pen, depth-1, contractBy*length, contractBy,branches,firstBranchAngle,nextBranchAngle)
pen.right(nextBranchAngle)
pen.setheading(heading)
pen.setposition(position)
# Ensures that multiple trees are created each at different coordinates.
for i in range(number1):
p1.sety(number2)
p1.setx(number3)
p1.down()
drawFern1(p1,d,length,contract,branch,first,next)
number2 = random.randint(-100,100)
number3 = random.randint(-100,100)
p1.up()
This code looks pretty solid to me, especially for a Python beginner. I've seen much worse.
If I were writing it, I think I'd calculate number2 and number3 only inside the main for loop - a priming definition as you have here is often convenient for a while loop, but not necessary in this case. I would also try to use more explanatory variable names, and depending on the problem statement I might require the randomly generated depth value to be at least 1 - if depth is generated as 0, nothing will be drawn.
My version of this would look like this:
import random
import turtle
def drawFern(pen, depth, length, contraction, branches, firstBranchAngle, nextBranchAngle):
if depth > 0:
# Pen's Position and heading
heading = pen.heading()
position = pen.position()
pen.width(depth)
pen.forward(length)
pen.left(firstBranchAngle)
for i in xrange(branches):
drawFern(pen, depth-1, contraction*length, contraction, branches, firstBranchAngle, nextBranchAngle)
pen.right(nextBranchAngle)
pen.setheading(heading)
pen.setposition(position)
# I'm using a python module called turtle to visualize results
# Creates a pen
pen = turtle.Pen()
# Shows pen drawing
pen.tracer(True)
pen.up()
pen.left(90)
# Configure initial state
# Varying depth of recursive fern
depth = random.randint(1,2)
# Length of branches
length = 150
# Varying degree of contraction
contraction = random.uniform(.5,1)
# Varying number of branches
branches = random.randint(5,8)
# Varying first degree of branch
first_angle = random.randint(30,70)
# Varying degree between each branches
next_angle = random.randint(1,30)
number_of_trees =random.randint(10,20)
for i in xrange(number_of_trees):
new_x = random.randint(-100, 100)
new_y = random.randint(-100, 100)
pen.setx(new_x)
pen.sety(new_y)
pen.down()
drawFern(pen, depth, length, contraction, branches, first_angle, next_angle)
pen.up()
In addition to moving the x and y coordinate randomization into the main loop, moving the recursive function definition earlier in the file, and using some more explicit variable names, I've used xrange calls instead of range calls - a trivial optimization if you're on Python 2.x. If you're on Python 3, range is correct. But these are minor changes.
You could also throw in an if clause before the range(branches) loop to not even try if depth equals 1 - that's another minor optimization, although not one that will make a big difference.
I thought my code was great until I showed my professor. He told my
code was too complicated and said I would need to simplify it.
This is rather complicated code given the quality of trees that it draws:
Drawing just vertical lines and blank screens are within the random parameters of the program as written! Let's rework the program to move some of the randomness from the static configuration code into the recursive routine itself. We'll also fine tune the random ranges a bit and clean up the code, primarily by eliminating variables that are only set and used once:
from random import randint, uniform
from turtle import Screen, Pen # Using python turtle module to visualize results
# Configure initial state
DEPTH = randint(3, 4) # Varying thickness and splitting of branches
LENGTH = randint(125, 150) # Length of branches
CONTRACT_BY = uniform(0.4, 0.8) # Varying degree of contraction
def drawFern(pen, depth, length, contractBy):
if depth < 1:
return
# Save pen's position and heading
heading = pen.heading()
position = pen.position()
pen.width(depth * 1.5) # pen thickness depends on branching
pen.forward(length)
pen.left(randint(30, 70)) # Varying first degree of branch)
for _ in range(randint(5, 8)): # Varying amount of branches
drawFern(pen, depth - 1, contractBy * length, contractBy)
pen.right(randint(5, 30)) # Varying degree between each branches
# Restore pen's Position and heading
pen.setheading(heading)
pen.setposition(position)
screen = Screen()
pen = Pen(visible=False)
pen.left(90)
screen.tracer(False)
# Ensure that multiple trees are created each at different coordinates.
for i in range(randint(10, 20)):
pen.penup()
pen.setposition(randint(-200, 200), randint(-300, 0))
pen.pendown()
drawFern(pen, DEPTH, LENGTH, CONTRACT_BY)
screen.tracer(True)
screen.mainloop()
I am using the matplotlib PatchCollection to hold a bunch of matplotlib.patches.Rectangles. But I want them to be invisible when first drawn (only turn visible when something else is clicked). This works fine when I was drawing the Rectangle's straight to the canvas with add_artist, but I want to change this to using a PatchCollection. For some reason, when I create the PatchCollection and add it with add_collection, they are all visible.
self.plotFigure = Figure()
self.plotAxes = self.plotFigure.add_subplot(111)
self.selectionPatches = []
for node in self.nodeList:
node.selectionRect = Rectangle((node.posX - node.radius*0.15 , node.posY - node.radius*0.15),
node.radius*0.3,
node.radius*0.3,
linewidth = 0,
facecolor = mpl.colors.ColorConverter.colors['k'],
zorder = z,
visible = False)
self.selectionPatches.append(node.selectionRect)
self.p3 = PatchCollection(self.selectionPatches, match_original=True)
self.plotAxes.add_collection(self.p3)
If I iterate through self.selectionPatches and print out each Rectangle's get_visible(), it returns false. But they are clearly visible when they get drawn. If anyone can help me see why this is happening, I would be very grateful.
When you create a PatchCollection it extracts a whole bunch of information from the objects you hand in (shape, location, styling(if you use match_original)), but does not keep the patch objects around for later reference (so it discards the per-patch visible). If you want all of the rectangles to be visible/invisible together you can do
self.p3 = PatchCollection(self.selectionPatches,
match_original=True,
visible=False)
other wise I think you will have to group them into the sets you want to appear together.
Look at the __init__ function of PatchCollection(here) and the rest of the cascade up through Collection and Artist.