I wrote an article Using an external editor for Python development of Grasshopper, but when I try to develop a Python program in earnest with Grasshopper, one file Then the code will not fit, so you will want to separate your own functions etc. in a separate file. Also, when reading an image file or CSV, or when creating a plug-in, it is necessary to manage the file structure firmly so that the file can be referenced by a relative path. This time, I will explain how to make it easier to manage the code by using your own modules and configuration files.
--Prevents the code from becoming too long and unmanageable --Easy to individually test your own functions and classes --By creating a configuration file, you can change the settings without having to mess with the code. ――It becomes easier to divert the function in another project --Packaging makes it easier to manage with git etc.
This time, I will explain with this file structure.
There are `gh_file.gh``` and
function.py``` directly under the project folder, and to call the module ``` mod.py``` in the folder ``
module Create `` `__ init__. Py
.
Also, create `radius_range.json``` in the folder
`data``` as a configuration file.
.
├── module
│ └── __init__.py
│ └── mod.py
├── data
│ └── radius_range.json
└── function.py
└── gh_file.gh
In this sample project, the following program will be used as an example.
--Use Pop2D with GH to generate multiple points at random locations --Enter a list of points in function.py --Call the mod.py function from function.py --Returns a random radius for each point in the range set by radius_range.json --Generate a circle with a random radius around each point with function.py
In the configuration file radius_range.json
, the "minimum value", "maximum value" and "step" to be included in the random function are defined.
radius_range.json
{
"min": 1,
"max": 10,
"step": 1
}
In the module `mod.py```, create a simple function that calls json in the configuration file and returns a random number. I would like to call this function called ``` random_radius``` from
`function.py```.
mod.py
# -*- coding: utf-8 -*-
import json
from io import open
import random
def random_radius():
#Relative path of json file
path = "./data/radius_range.json"
#open json file
with open(path, encoding='utf-8') as f:
d = json.load(f)
#Get parameters from config file
min = d['min']
max = d['max']
step = d['step']
#Returns a random number
return random.randrange(min,max,step)
The GH file gh_file.gh
is set like this.
In Read File, right-click F → Select one existing file to function.Specify py.
Please refer to [Use an external editor for Python development of Grasshopper](https://qiita.com/keiwatanabe/items/9eb6a7d6749f5e586f7f) for the setting to read an external file.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263714/1f8b46bc-c4e4-a41d-84e7-474c58cd383f.png)
# GHPython file directory
Now for the main subject, let's try the following code in function.py to understand why we are writing this article.
#### **`function.py`**
```python
import rhinoscriptsyntax as rs
from module import mod
a = mod.random_radius()
Then, I think that such an error will appear.
1. Solution exception:path'C:\Program Files\Rhino 6\System\data\radius_range.json'Some of them were not found.
When I read the error message, it says that radius_range.json
cannot be found.
I can call `mod.py``` because I have gone to the point of searching for the json file, but it seems that the json file has gone to search for
Program Files```. I'm calling ``
function.py in the same directory from a GH file in the same directory, but for some reason I'm referencing `` `Program Files
. ..
** Why can't I refer to radius_range.json correctly even though mod.py can be read correctly? ** **
To understand the cause, you need to understand the ** module search path ** and the ** current directory **.
This is a list of paths that Python will look for when importing standard or external libraries. To check this, try the code below in the same GH file.
import sys
print(sys.path)
Then it will be returned like this.
The 'Z: \\ Projects \\ demo-ghpython-package'
at the beginning of this is the directory where I saved this project file and the location where the GH file is stored.
['Z:\\Projects\\demo-ghpython-package', 'C:\\Program Files\\Rhino 6\\Plug-ins\\IronPython\\Lib', 'C:\\Users\\[username]\\AppData\\Roaming\\McNeel\\Rhinoceros\\6.0\\Plug-ins\\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\\settings\\lib', 'C:\\Users\\[username]\\AppData\\Roaming\\McNeel\\Rhinoceros\\6.0\\scripts']
In other words, modules in the same directory as the GH file can be imported by following this path. Now you know why `` `mod.py``` could be imported.
The current directory is where Python is running. To check this, try the code below in the same GH file as before.
import os
print(os.getcwd())
Then, in my case, the result is returned as follows.
C:\Program Files\Rhino 6\System
Apparently the Python code for the GH file was running inside Rhino 6 in Program Files
.
When referring to the json file, it was described as ** relative path ** like `` `./data/~~.json```, so look for the json file in the data directory in the above path. I said, there is no such file! It seems that an error occurred.
There are two ways.
I think that it is better to specify it with an absolute path, but it works when the data is stored in the same project file like this time or when the same code may be executed on another PC. No. Therefore, this time we will use method 2.
Change to `` `function.py``` to move the current directory as follows.
function.py
import rhinoscriptsyntax as rs
from module import mod
import os
#Get the directory containing the GH file = project folder
base_dir = os.path.dirname(ghdoc.Path)
#Move current directory to project folder
os.chdir(base_dir)
a = mod.random_radius()
-- ghdoc.Path
returns the path of the GH file being executed, so in this case the directory path of that path will be the path of the project folder, so set it to `base_dir``` I will. --Move the current directory to
`base_dirwith
os.chdir```.
Then, a random number came back from a safely.
Originally I wanted to output from a a circle object, so change the code to write a circle with the returned random number as the radius.
function.py
import rhinoscriptsyntax as rs
from module import mod
import os
#Get the directory containing the GH file = project folder
base_dir = os.path.dirname(ghdoc.Path)
#Move current directory to project folder
os.chdir(base_dir)
circles = []
for pt in pts:
#Define a plane that draws a circle
plane = rs.MovePlane(rs.WorldXYPlane(), pt)
#Get a random radius
radius = mod.random_radius()
#Generate a circle and add it to the list
circles.append(rs.AddCircle(plane,radius))
a = circles
The yen is finally returned. Although I worked hard, the result is sober lol
This time it was a simple program that writes a random range in a configuration file, reads it using a module and passes it to the main program, but it is very effective when reading image files and a large amount of CSV. Please refer to it when creating a plug-in with Python.
https://note.nkmk.me/python-os-getcwd-chdir/
https://note.nkmk.me/python-import-module-search-path/
Recommended Posts