Generating Mathematical Artwork For NFTs Through Samila And Python

Greetings! Some links on this site are affiliate links. That means that, if you choose to make a purchase, The Click Reader may earn a small commission at no extra cost to you. We greatly appreciate your support!

Today, non fungible tokens (NFTs) are one of the most talked about topics in the cryptoworld. In light of this, this lesson covers how you can make actual artworks using mathematics through an open-source Python package called Samila.

The concept behind what Samila is based upon is simple to understand: when you transform a square-shaped space from the Cartesian coordinate system to any other arbitrary coordinate system, you generate a plot that feels like art.

Generating Mathematical Artwork For NFTs Through Samila And Python

Installing and Importing Samila in Python

You can install Samila using the Python Package Manager (pip).

For this tutorial, we will be using version 0.3 since it is the latest release of the package. Open up your command line/terminal and execute the following command to install Samila.

pip install samila==0.3

To test if your installation is correct, you can try out the following line of import,

import samila

If you do not get any error when executing this import, then, you’ve successfully installed and imported Samila in Python. Now, let’s move on to create our generative art.

Getting Started with Samila

Let us start by importing the necessary libraries,

# Importing necessary libraries
import random
import math
import matplotlib.pyplot as plt

from samila import GenerativeImage, Projection

Now, let us define two functions according to Samila’s GitHub example to create our transformations,

def f1(x, y):
    result = random.uniform(-1,1) * x**2  - math.sin(y**2) + abs(y-x)
    return result

def f2(x, y):
    result = random.uniform(-1,0) * y**3 - math.cos(x**2) + 2*x
    return result

Now, we simply use the GenerativeImage class and its methods generate() and plot() to create generative art.

Note: We will dive deep into how these values are generated and plotted by looking at the actual code behind the two methods later down this tutorial. Hopefully, by then, you will be able to contribute to Samila on your own. But, for now, let us simply see what kind of art Samila can generate.

DEFAULT_SEED = 1018273

g = GenerativeImage(f1, f2)
g.generate(seed=DEFAULT_SEED)
g.plot(size=(8,8))
Mathematical Artwork - Generating Mathematical Artwork For NFTs Through Samila And Python

You can also specify the projection during plotting,

g.plot(projection=Projection.POLAR, size=(8,8))
Mathematical Artwork - Generating Mathematical Artwork For NFTs Through Samila And Python

You can also specify a new range for your square-shaped space to transform. The default is -pi to pi with a step of 0.01.

g = GenerativeImage(f1,f2)
g.generate(start = -2*math.pi, step=0.01, stop=0)
g.plot(size=(8,8))
Mathematical Artwork - Generating Mathematical Artwork For NFTs Through Samila And Python

Finally, you can also add color to the generated artwork,

g.plot(color="yellow", bgcolor="black", projection=Projection.POLAR, size=(8,8))
Mathematical Artwork - Generating Mathematical Artwork For NFTs Through Samila And Python

Saving your art locally using Samila

Samila provides the save_image() method to save your image locally.

g.save_image(file_adr="myart.png")

You can use the depth parameter to save a higher resolution picture.

g.save_image(file_adr="myart.png", depth=5)

Saving your art in NFT Storage

NFT Storage is a free decentralized storage that lets users store their NFT content and metadata seamlessly and securely with IPFS and Filecoin. You can read more about it detail through the blog written by Filecoin.

You can upload your generated images directly to NFT.storage using the nft_storage() method and by passing in your API key.

g.nft_storage(api_key = YOUR_API_KEY)

How do the generate() and plot() methods work?

Now, let us take a deep dive into the code that is working under the hood to generate the values and plot them. The methods we will discuss can be found in genimage.py.

  • generate()

Let us see how the two functions that we defined earlier (f1 and f2) are used to generate values for plotting.

# Importing necessary library
import itertools

# Setting constant values
DEFAULT_START = -1 * math.pi
DEFAULT_STOP = math.pi
DEFAULT_STEP = 0.01

# Creating a helper function
def float_range(start, stop, step):
    while start < stop:
        yield float(start)
        start += step

Now, creating two ranges from -pi to pi with a step of 0.01. Here two ranges are created since we need both x-axis and y-axis coordinates for plotting.

range1 = list(float_range(start = DEFAULT_START, stop = DEFAULT_STOP, step = DEFAULT_STEP))
range2 = list(float_range(start = DEFAULT_START, stop = DEFAULT_STOP, step = DEFAULT_STEP))

Finding the cartesian product of the two ranges,

range_prod = list(itertools.product(range1, range2))

Finally, generating the values for plotting by passing them through our functions,

data1 = []
data2 = []

for item in range_prod:
    random.seed(DEFAULT_SEED)
    data1.append(f1(item[0], item[1]).real)
    data2.append(f2(item[0], item[1]).real)

We have now successfully generated the x-axis and y-axis values for plotting.

  • plot()

Next, let us see how data1 and data2 are plotted out. First, we will start by defining some constants,

# Setting valid colors for plotting
from matplotlib import colors as mcolors
VALID_COLORS = list(dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS).keys())

# Setting default parameters
DEFAULT_COLOR = "black"
DEFAULT_BACKGROUND_COLOR = "white"
DEFAULT_ALPHA = 0.1
DEFAULT_IMAGE_SIZE = (10, 10)
DEFAULT_SPOT_SIZE = 0.01
DEFAULT_PROJECTION = None

Next, creating helper functions for calculating Levenshtein distance between two words as well as for filtering a given color and returning it.

def distance_calc(s1, s2):
    """
    Calculate Levenshtein distance between two words.
    :param s1: first string
    :type s1 : str
    :param s2: second string
    :type s2 : str
    :return: distance between two string
    References :
    1- https://stackoverflow.com/questions/2460177/edit-distance-in-python
    2- https://en.wikipedia.org/wiki/Levenshtein_distance
    """
    if len(s1) > len(s2):
        s1, s2 = s2, s1

    distances = range(len(s1) + 1)
    for i2, c2 in enumerate(s2):
        distances_ = [i2 + 1]
        for i1, c1 in enumerate(s1):
            if c1 == c2:
                distances_.append(distances[i1])
            else:
                distances_.append(
                    1 + min((distances[i1], distances[i1 + 1], distances_[-1])))
        distances = distances_
    return distances[-1]

def filter_color(color):
    """
    Filter given color and return it.
    :param color: given color
    :type color: str or tuple
    :return: filtered version of color
    """
    if isinstance(color, tuple):
        return color
    if isinstance(color, str):
        distance_list = list(map(lambda x: distance_calc(color, x),
                                 VALID_COLORS))
        min_distance = min(distance_list)
        return VALID_COLORS[distance_list.index(min_distance)]
    return None

Mapping the colors and background color,

color, bgcolor = map(filter_color, [DEFAULT_COLOR, DEFAULT_BACKGROUND_COLOR])

Creating the final plot,

fig = plt.figure()
fig.set_size_inches(DEFAULT_IMAGE_SIZE[0], DEFAULT_IMAGE_SIZE[1])
fig.set_facecolor(bgcolor)
ax = fig.add_subplot(111)
ax.set_facecolor(bgcolor)
ax.scatter(
    data2,
    data1,
    alpha=DEFAULT_ALPHA,
    edgecolors=color,
    s=DEFAULT_SPOT_SIZE)
ax.set_axis_off()
ax.patch.set_zorder(-1)
ax.add_artist(ax.patch)
Mathematical Artwork - Generating Mathematical Artwork For NFTs Through Samila And Python

In Conclusion

That is it for this lesson on Generating Mathematical Artwork For NFTs Through Samila And Python.

If you are interested in more things like this, The Click Reader provides you a large collection of data science resources to study from—check it out by clicking here.

Leave a Comment