Skip to content

turn some text into a mobius surface¤

a good reference was: https://algebra-fun.gitee.io/blog/2020/06/16/Joy-%E7%BB%98%E5%88%B6Mobius/

    if __import__("sys").platform == "emscripten":
        await __import__("micropip").install("pandas matplotlib ipympl".split())
    import pandas, matplotlib, io, numpy
    from mpl_toolkits.mplot3d import Axes3D
    %matplotlib agg

get_text transforms some text into a dataframe that will allow us to plot a mobius strip.

    def get_text(text="deathbeds", repeat=2):
        return get_text_array(
            get_text_figure(text, repeat)
        ).pipe(get_parameterized_text).pipe(get_xyz)

get_text_figure transforms text to pixels.

    def get_text_figure(text="deathbeds", repeat=1):
        matplotlib.pyplot.gca().text(0, 0, text*repeat, size=1000)
        matplotlib.pyplot.gca().axis("off")
        fig = matplotlib.pyplot.gcf()
        return fig

get_text_array structure those pixels as dataframe

    def get_text_array(fig):
        data= io.BytesIO()
        fig.savefig(data, bbox_inches="tight")
        data.seek(0)
        where = numpy.where(matplotlib.pyplot.imread(data).sum(2)[::-4, ::20] < 2)
        return pandas.concat(
            [pandas.Series(where[0], name="x"), pandas.Series(where[1], name="y")], axis=1
        ).set_index("x")

get_parameterized_text parameterizes x onto 0..1 and s one 0..2π

    def get_parameterized_text(df):
        extent = df.index.max() - df.index.min()
        df["t"] = df.index.to_series()
        df.t = df.t.sub(df.t.min()).div(extent).sub(.5)
        extent = df.y.max() - df.y.min()
        df["s"] = df.y.add(df.y.min()).div(extent).mul(2*numpy.pi)
        return df

get_xyz moves the parameterization in xyz space.

    def get_xyz(df, R=100, W=50):
        return df.assign(
            x=(R+W*df.t*df.s.div(2).apply(numpy.cos))*df.s.apply(numpy.cos), 
            y=(R+W*df.t*df.s.div(2).apply(numpy.cos))*df.s.apply(numpy.sin), 
            z=W*df.t.mul(df.s.div(2).apply(numpy.sin)), 
        )

get_plot takes our structured data and plots in 3d.

    def get_plot(df):
        fig = matplotlib.pyplot.gcf()
        ax = Axes3D(fig, auto_add_to_figure=False)
        fig.add_axes(ax)
        ax.scatter3D(df.x, df.y, df.z, c=[(.1, .1, .1, .015)], marker="v", s=200, edgecolor=None)
        return fig

use the interactive 3-d dispklay

    %matplotlib ipympl

plot it all

    matplotlib.pyplot.gcf().set_size_inches((6, 6))        
    get_text("deathbeds").pipe(get_plot)
No description has been provided for this image
Figure
No description has been provided for this image