import%20marimo%0A%0A__generated_with%20%3D%20%220.23.4%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%20%60transformnd%60%20tutorial%0A%0A%20%20%20%20%60transformnd%60%20is%20a%20python%20library%20which%20provides%20implementations%20of%20coordinate%20transformations%2C%20base%20classes%20to%20ensure%20a%20consistent%20API%20across%20implementations%2C%20and%20utilities%20for%20combining%20and%20working%20with%20those%20coordinate%20transformations.%0A%0A%20%20%20%20First%2C%20define%20a%20basic%20shape%2C%20and%20make%20a%20function%20for%20plotting%20it%3A%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20from%20matplotlib%20import%20pyplot%20as%20plt%0A%20%20%20%20from%20matplotlib.patches%20import%20Polygon%0A%0A%20%20%20%20rng%20%3D%20np.random.default_rng(1991)%0A%0A%20%20%20%20%23%20Array%20of%20N%20coordinates%20in%20D%20dimensions%20has%20shape%20NxD%0A%20%20%20%20square%20%3D%20np.array(%0A%20%20%20%20%20%20%20%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B0%2C%200%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B0%2C%201%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B1%2C%201%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%5B1%2C%200%5D%2C%0A%20%20%20%20%20%20%20%20%5D%0A%20%20%20%20)%0A%0A%20%20%20%20def%20plot_shape(**kwargs)%3A%0A%20%20%20%20%20%20%20%20%22%22%22Draw%20a%20labelled%20polygon%20from%20kwargs%20like%20name%3Dcoords.%22%22%22%0A%20%20%20%20%20%20%20%20fig%2C%20ax%20%3D%20plt.subplots()%0A%20%20%20%20%20%20%20%20min_%20%3D%20-1%0A%20%20%20%20%20%20%20%20max_%20%3D%203%0A%20%20%20%20%20%20%20%20ax.set_xlim(min_%2C%20max_)%0A%20%20%20%20%20%20%20%20ax.set_ylim(min_%2C%20max_)%0A%20%20%20%20%20%20%20%20ax.hlines(0%2C%20min_%2C%20max_%2C%20colors%3D%22k%22)%0A%20%20%20%20%20%20%20%20ax.vlines(0%2C%20min_%2C%20max_%2C%20colors%3D%22k%22)%0A%20%20%20%20%20%20%20%20ax.set_aspect(%22equal%22)%0A%20%20%20%20%20%20%20%20sq%20%3D%20Polygon(square%2C%20closed%3DFalse%2C%20color%3D%22grey%22%2C%20label%3D%22original%22)%0A%20%20%20%20%20%20%20%20ax.add_patch(sq)%0A%0A%20%20%20%20%20%20%20%20cmap%20%3D%20plt.get_cmap(%22tab10%22)%0A%0A%20%20%20%20%20%20%20%20for%20idx%2C%20(name%2C%20coords)%20in%20enumerate(kwargs.items())%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20poly%20%3D%20Polygon(coords%2C%20closed%3DFalse%2C%20label%3Dname%2C%20color%3Dcmap(idx))%0A%20%20%20%20%20%20%20%20%20%20%20%20ax.add_patch(poly)%0A%20%20%20%20%20%20%20%20ax.legend()%0A%20%20%20%20%20%20%20%20return%20fig%0A%0A%20%20%20%20plot_shape()%0A%20%20%20%20return%20np%2C%20plot_shape%2C%20rng%2C%20square%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20Now%20we'll%20add%20some%20basic%20transformations.%0A%0A%20%20%20%20Transformations%20are%20subclasses%20of%20the%20%60Transform%60%20abstract%20base%20class.%0A%20%20%20%20Once%20the%20transformation%20is%20instantiated%2C%20it%20can%20be%20used%20just%20like%20a%20function%2C%20transforming%20a%20numpy%20array%20of%20coordinates%20into%20a%20new%20numpy%20array.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_shape%2C%20square)%3A%0A%20%20%20%20from%20transformnd.transforms.simple%20import%20Scale%2C%20Translate%0A%0A%20%20%20%20translate%20%3D%20Translate(%5B1.5%2C%200%5D)%0A%20%20%20%20scale%20%3D%20Scale(%5B0.5%2C%202%5D)%0A%0A%20%20%20%20plot_shape(%0A%20%20%20%20%20%20%20%20translated%3Dtranslate.apply(square)%2C%0A%20%20%20%20%20%20%20%20scaled%3Dscale.apply(square)%2C%0A%20%20%20%20)%0A%20%20%20%20return%20Scale%2C%20Translate%2C%20scale%2C%20translate%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20%60TransformSequence%60%0A%0A%20%20%20%20Transforms%20can%20be%20chained%20together%20into%20a%20single%20transformation%2C%20with%20the%20%60TransformSequence%60%20class.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_shape%2C%20scale%2C%20square%2C%20translate)%3A%0A%20%20%20%20from%20transformnd%20import%20TransformSequence%0A%0A%20%20%20%20scale_then_translate%20%3D%20TransformSequence(%5Bscale%2C%20translate%5D)%0A%0A%20%20%20%20plot_shape(%0A%20%20%20%20%20%20%20%20translated%3Dtranslate.apply(square)%2C%0A%20%20%20%20%20%20%20%20scaled%3Dscale.apply(square)%2C%0A%20%20%20%20%20%20%20%20scaled_then_translated%3Dscale_then_translate.apply(square)%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Composing%20and%20inverting%20transformations%0A%0A%20%20%20%20%60TransformSequences%60%20can%20also%20be%20constructed%20with%20the%20%60%7C%60%20operator.%0A%0A%20%20%20%20Certain%20transformations%20can%20be%20inverted%20with%20the%20%60~%60%20operator.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(plot_shape%2C%20scale%2C%20square%2C%20translate)%3A%0A%20%20%20%20translate_scale%20%3D%20translate%20%7C%20scale%0A%20%20%20%20%23%20Note%20that%20translate%20-%3E%20scale%20gives%20different%20results%20to%20scale%20-%3E%20translate%20above%0A%20%20%20%20%23%20because%20the%20scaling%20is%20done%20around%20(0%2C%200)%0A%0A%20%20%20%20undo_translate_scale%20%3D%20~translate_scale%0A%20%20%20%20%23%20Note%20that%20if%20you%20want%20to%20immediately%20call%20an%20inverted%20transform%2C%0A%20%20%20%20%23%20you%20need%20to%20use%20brackets%20to%20ensure%20the%20inversion%20happens%20first%3A%0A%20%20%20%20%23%0A%20%20%20%20%23%20%20%20%20%20(~my_transform)(my_coordinates)%0A%0A%20%20%20%20plot_shape(%0A%20%20%20%20%20%20%20%20translated_scaled%3Dtranslate_scale.apply(square)%2C%0A%20%20%20%20%20%20%20%20undone%3Dundo_translate_scale.apply(translate_scale.apply(square))%2C%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Affine%20transformations%0A%0A%20%20%20%20A%20common%20class%20of%20coordinate%20transformations%20are%20affine%20transformations.%0A%20%20%20%20These%20require%20a%20transformation%20matrix%20which%20then%20multiplies%20the%20coordinate%20array.%0A%20%20%20%20%60transformnd%60%20provides%20convenience%20methods%20for%20constructing%20this%20transformation%20matrix%20out%20of%20common%20operations%3A%20translations%2C%20scales%2C%20reflections%2C%20rotations%2C%20and%20shears.%0A%0A%20%20%20%20Because%20this%20all%20uses%20matrix%20multiplication%20under%20the%20hood%2C%20%60AffineTransform%60%20instances%20can%20be%20composed%20using%20the%20matrix%20multiplication%20operator%20%60%40%60%20rather%20than%20needing%20to%20apply%20the%20transforms%20one%20at%20a%20time%20in%20a%20%60TransformSequence%60.%0A%0A%20%20%20%20Note%20that%2C%20as%20with%20raw%20affine%20transformation%20matrices%2C%20the%20individual%20transformations%20are%20effectively%20applied%20right%20to%20left.%0A%20%20%20%20That%20is%2C%20to%20apply%20a%20scale%2C%20then%20a%20rotation%2C%20then%20a%20translation%2C%20use%20%60(translation%20%40%20rotation%20%40%20scale).apply(coordinates)%60.%0A%0A%20%20%20%20Affine%20transformations%20are%20invertible.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20plot_shape%2C%20square)%3A%0A%20%20%20%20from%20transformnd.transforms.affine%20import%20Affine%0A%0A%20%20%20%20sca%20%3D%20Affine.scaling(%5B1.5%2C%201%5D)%0A%20%20%20%20rot%20%3D%20Affine.rotation2(45)%20%20%23%20Only%202D%2C%203D%20have%20convenient%20constructors%0A%20%20%20%20tran%20%3D%20Affine.translation(%5B1%2C%200%5D)%0A%20%20%20%20sca_rot_tran%20%3D%20tran%20%40%20rot%20%40%20sca%0A%0A%20%20%20%20plot_shape(%0A%20%20%20%20%20%20%20%20translated%3Dtran.apply(square)%2C%0A%20%20%20%20%20%20%20%20rotated%3Drot.apply(square)%2C%0A%20%20%20%20%20%20%20%20scaled%3Dsca.apply(square)%2C%0A%20%20%20%20%20%20%20%20translated_rotated_scaled%3Dsca_rot_tran.apply(square)%2C%0A%20%20%20%20)%0A%20%20%20%20assert%20np.allclose(%0A%20%20%20%20%20%20%20%20(tran%20%40%20rot%20%40%20sca).apply(square)%2C%20(sca%20%7C%20rot%20%7C%20tran).apply(square)%0A%20%20%20%20)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Spaces%20and%20bridging%20transforms%0A%0A%20%20%20%20A%20common%20task%20in%20coordinate%20transformation%20is%20to%20convert%20coordinates%20in%20one%20space%20(e.g.%20a%20pixel%20index%20of%20an%20image)%20into%20some%20other%20space%20(e.g.%20a%20location%20in%20%22world%22%20space%2C%20using%20the%20image's%20resolution%20and%20offset).%0A%0A%20%20%20%20All%20%60Transform%60s%20can%20take%20the%20keyword%20arguments%20%60spaces%60%20on%20instantiation%2C%20which%20is%20a%20tuple%20of%20two%20hashable%20values%20(e.g.%20a%20string%20or%20number).%0A%20%20%20%20If%20not%20%60None%60%2C%20these%20values%20act%20as%20a%20reference%20to%20the%20spaces%20the%20transform%20goes%20from%20and%20to%20respectively.%0A%20%20%20%20This%20makes%20it%20easier%20to%20reason%20about%20what%20space%20the%20coordinates%20start%20and%20end%20in.%0A%0A%20%20%20%20%60TransformSequence%60%20instances%20check%20that%20consecutive%20transforms%20in%20the%20sequence%20refer%20to%20consistent%20spaces%20(if%20spaces%20are%20defined).%0A%20%20%20%20They%20will%20also%20use%20a%20transform%20with%20a%20defined%20target%20space%20to%20infer%20the%20source%20space%20of%20the%20next%20transform%2C%20if%20undefined.%0A%0A%20%20%20%20Once%20you%20have%20a%20set%20of%20transforms%20between%20different%20defined%20spaces%2C%20you%20can%20do%20bridging%20transforms%3A%20calculating%20how%20to%20get%20from%20one%20space%20to%20another%20by%20applying%20some%20subset%20of%20those%20transforms%20in%20sequence.%0A%20%20%20%20This%20uses%20the%20%60TransformGraph%60%20class%20(requires%20%60networkx%60).%0A%0A%20%20%20%20The%20%60TransformGraph%60%20will%20automatically%20unpack%20any%20transforms%20inside%20sequences%20(if%20they%20have%20spaces%20defined)%2C%20and%20infer%20inverse%20transforms%20where%20possible.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Scale%2C%20Translate)%3A%0A%20%20%20%20from%20transformnd.graph%20import%20TransformGraph%0A%20%20%20%20from%20transformnd%20import%20Spaces%0A%0A%20%20%20%20g%20%3D%20TransformGraph()%0A%20%20%20%20ab%20%3D%20Scale(%5B2%2C%202%5D%2C%20spaces%3DSpaces(%22a%22%2C%20%22b%22))%0A%20%20%20%20bc%20%3D%20Translate(%5B0.5%2C%201%5D%2C%20spaces%3DSpaces(%22b%22%2C%20%22c%22))%0A%20%20%20%20bd%20%3D%20Translate(%5B1%2C%200.5%5D%2C%20spaces%3DSpaces(%22b%22%2C%20%22d%22))%0A%0A%20%20%20%20g.add_transform(ab)%0A%20%20%20%20g.add_transform(ab.invert())%0A%20%20%20%20g.add_transform(bc)%0A%20%20%20%20g.add_transform(bc.invert())%0A%20%20%20%20g.add_transform(bd)%0A%20%20%20%20g.add_transform(bd.invert())%0A%0A%20%20%20%20print(%22Transform%20sequence%20from%20a%20to%20c%3A%22%2C%20g.get_sequence(%22a%22%2C%20%22c%22))%0A%20%20%20%20print(%22Transform%20sequence%20from%20d%20to%20a%3A%22%2C%20g.get_sequence(%22d%22%2C%20%22a%22))%0A%20%20%20%20return%20(Spaces%2C)%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Making%20your%20own%20%60Transform%60%0A%0A%20%20%20%20There%20are%20many%20different%20types%20of%20transformation%2C%20which%20have%20been%20implemented%20in%20many%20different%20ways%20in%20many%20different%20libraries.%0A%20%20%20%20%60transformnd%60%20makes%20it%20easy%20to%20bring%20lots%20of%20different%20implementations%20under%20one%20interface%2C%20which%20can%20then%20make%20use%20of%20the%20same%20composition%20tools.%0A%0A%20%20%20%20%60Transform%60%20is%20an%20abstract%20base%20class%20with%20a%20number%20of%20utility%20methods%20already%20implemented.%0A%20%20%20%20At%20a%20minimum%2C%20you%20just%20need%20to%20subclass%20it%20and%20implement%20the%20%60.apply%60%20method.%0A%20%20%20%20If%20your%20transformation%20is%20only%20defined%20for%20certain%20dimensionalities%2C%20that%20can%20also%20be%20specified%3A%20use%20the%20%60._validate_coords%60%20method%20to%20check%20that%20passed-in%20coordinates%20are%20of%20the%20right%20shape.%20%5B1%5D%0A%0A%20%20%20%20You%20can%20also%20optionally%20implement%20%60.__invert__%60%2C%20if%20the%20transformation%20is%20invertible.%0A%0A%20%20%20%20%5B1%5D%3A%20N.B.%20%60TransformSequence%60%20and%20%60TransformGraph%60%20both%20ensure%20that%20their%20component%20transforms%20have%20compatible%20dimensionalities.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Spaces%2C%20np)%3A%0A%20%20%20%20from%20transformnd%20import%20Transform%2C%20NDims%0A%0A%20%20%20%20class%20IsotropicScale2d(Transform)%3A%0A%20%20%20%20%20%20%20%20def%20__init__(self%2C%20factor%3A%20float%2C%20*%2C%20spaces%3DSpaces(None%2C%20None))%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20ensure%20the%20spaces%20are%20handled%20properly%0A%20%20%20%20%20%20%20%20%20%20%20%20super().__init__(ndims%3DNDims(2%2C%202)%2C%20spaces%3Dspaces)%0A%20%20%20%20%20%20%20%20%20%20%20%20self.factor%20%3D%20factor%0A%0A%20%20%20%20%20%20%20%20def%20apply(self%2C%20coords%3A%20np.ndarray)%20-%3E%20np.ndarray%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%23%20ensure%20the%20coordinates%20are%20of%20the%20right%20shape%0A%20%20%20%20%20%20%20%20%20%20%20%20coords%20%3D%20self._validate_coords(coords)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20coords%20*%20self.factor%0A%0A%20%20%20%20%20%20%20%20def%20invert(self)%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20type(self)(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%201%20%2F%20self.factor%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20spaces%3Dself.spaces.invert()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20)%0A%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%23%23%20Adapters%0A%0A%20%20%20%20Lots%20of%20objects%20have%20coordinates%2C%20but%20many%20other%20features%20too.%0A%20%20%20%20%60transformnd%60%20makes%20it%20easy%20to%20transform%20arbitrary%20python%20objects%20like%20this%20using%20adapters.%0A%20%20%20%20Basically%2C%20you%20define%20a%20subclass%20of%20%60transformnd.adapters.BaseAdapter%60%20and%20implement%20%60.apply%60%2C%20which%20takes%20a%20transform%20and%20an%20object.%0A%20%20%20%20This%20method%20will%20get%20coordinates%20from%20the%20object%2C%20and%20construct%20a%20new%20one%20from%20the%20transformed%20coordinates%20and%20the%20old%20object.%0A%0A%20%20%20%20For%20cases%20where%20an%20object%20has%20transformable%20attributes%2C%20there%20is%20the%20%60AttrAdapter%60%2C%20which%20takes%20key-value%20pairs%20of%20the%20name%20of%20the%20transformable%20attribute%2C%20and%20an%20adapter%20which%20knows%20how%20to%20apply%20a%20transform%20to%20that%20attribute.%0A%20%20%20%20Cases%20where%20the%20attribute%20is%20just%20a%20coordinate%20array%20can%20use%20the%20%60NullAdapter%60.%0A%0A%20%20%20%20If%20you're%20going%20to%20use%20the%20same%20adapter-transform%20combination%20a%20lot%2C%20you%20can%20use%20%60Adapter.partial%60%20to%20create%20a%20callable%20representing%20that%20combination.%0A%0A%20%20%20%20When%20writing%20your%20own%20%60Adapter%60%2C%20consider%20giving%20the%20%60.apply%60%20method%20an%20%60in_place%60%20keyword%20argument%20if%20you%20have%20the%20option%20of%20modifying%20the%20existing%20object%20rather%20than%20creating%20a%20new%20one.%0A%20%20%20%20%60AttrAdapter%60s%20which%20compose%20over%20other%20adapters%20will%20save%20themselves%20some%20copying%20by%20using%20this%20argument%20intelligently.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(np%2C%20rng%2C%20translate)%3A%0A%20%20%20%20from%20dataclasses%20import%20dataclass%0A%0A%20%20%20%20from%20transformnd.adapters%20import%20AttrAdapter%2C%20ReshapeAdapter%0A%0A%20%20%20%20%23%202D%20coordinates%20arranged%20in%20an%20array%0A%20%20%20%20odd_shaped_coordinates%20%3D%20rng.random((5%2C%203%2C%202%2C%204))%0A%20%20%20%20reshape%20%3D%20ReshapeAdapter(2)%20%20%23%20the%20axis%20containing%20each%20coordinate%0A%20%20%20%20odd_shaped_transformed%20%3D%20reshape.apply(translate%2C%20odd_shaped_coordinates)%0A%20%20%20%20assert%20odd_shaped_coordinates.shape%20%3D%3D%20odd_shaped_transformed.shape%0A%0A%20%20%20%20%23%20Custom%20class%3A%0A%0A%20%20%20%20%40dataclass%0A%20%20%20%20class%20Town%3A%0A%20%20%20%20%20%20%20%20houses%3A%20np.ndarray%0A%20%20%20%20%20%20%20%20shops%3A%20np.ndarray%0A%0A%20%20%20%20my_town%20%3D%20Town(%0A%20%20%20%20%20%20%20%20houses%3Drng.random((5%2C%202))%2C%0A%20%20%20%20%20%20%20%20shops%3Drng.random((3%2C%202))%2C%0A%20%20%20%20)%0A%0A%20%20%20%20%23%20None%20says%20%22this%20variable%20doesn't%20need%20adapting%20for%20transformation%22%0A%20%20%20%20%23%20i.e.%20it's%20already%20a%20numpy%20array%20of%20the%20correct%20shape%0A%20%20%20%20town_adapter%20%3D%20AttrAdapter(houses%3DNone%2C%20shops%3DNone)%0A%20%20%20%20translated_town%20%3D%20town_adapter.apply(translate%2C%20my_town)%0A%0A%20%20%20%20town_translator%20%3D%20town_adapter.partial(translate)%0A%20%20%20%20translated_town_2%20%3D%20town_translator(translated_town)%20%20%23%20noqa%3A%20F841%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(%22%22%22%0A%20%20%20%20%60transformnd%60%20includes%20adapters%20for%20instances%20of%20%60meshio.Mesh%60%2C%20%60pandas.DataFrame%60%20(where%20certain%20columns%20make%20up%20a%20coordinate%20array)%2C%20and%20geometries%20from%20%60shapely%60.%0A%20%20%20%20These%20are%20only%20available%20if%20you%20have%20the%20requisite%20dependencies%20installed.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_(Scale%2C%20np)%3A%0A%20%20%20%20import%20pandas%20as%20pd%0A%0A%20%20%20%20from%20transformnd.adapters.pandas%20import%20PandasAdapter%0A%0A%20%20%20%20df%20%3D%20pd.DataFrame(%0A%20%20%20%20%20%20%20%20np.random.random((3%2C%205))%2C%0A%20%20%20%20%20%20%20%20columns%3D%5B%22x%22%2C%20%22y%22%2C%20%22z%22%2C%20%22radius%22%2C%20%22weight%22%5D%2C%0A%20%20%20%20)%0A%0A%20%20%20%20print(%22original%22)%0A%20%20%20%20print(df)%0A%0A%20%20%20%20print(%22%5Cnscaled%22)%0A%20%20%20%20xyz_adapter%20%3D%20PandasAdapter(%5B%22x%22%2C%20%22y%22%2C%20%22z%22%5D)%0A%20%20%20%20scale3d%20%3D%20Scale(%5B1%2C%2010%2C%20100%5D)%0A%20%20%20%20print(xyz_adapter.apply(scale3d%2C%20df))%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
3ce8264d6a792c2f3d875e0a513eb3dd