Thanks to theidioms.com

## Generating Mathematical Artwork For NFTs Through Samila And Python # Generating Mathematical Artwork For NFTs Through Samila And Python

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.

## 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))```

You can also specify the projection during plotting,

`g.plot(projection=Projection.POLAR, size=(8,8))`

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))```

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

`g.plot(color="yellow", bgcolor="black", projection=Projection.POLAR, size=(8,8))`

## 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, item).real)
data2.append(f2(item, item).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, DEFAULT_IMAGE_SIZE)
fig.set_facecolor(bgcolor)
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)