{"id":30028973,"url":"https://github.com/drhdev/epicycles-plot","last_synced_at":"2025-10-16T13:18:00.448Z","repository":{"id":306770785,"uuid":"1027130904","full_name":"drhdev/epicycles-plot","owner":"drhdev","description":"Python Scripts to plot Epicycles.","archived":false,"fork":false,"pushed_at":"2025-07-27T13:15:05.000Z","size":553,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-27T15:21:48.476Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/drhdev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-27T11:33:23.000Z","updated_at":"2025-07-27T13:15:09.000Z","dependencies_parsed_at":"2025-07-27T15:22:01.941Z","dependency_job_id":"bf1066bb-6fd0-483a-bc7d-45599925c14f","html_url":"https://github.com/drhdev/epicycles-plot","commit_stats":null,"previous_names":["drhdev/epicycles-plot"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/drhdev/epicycles-plot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drhdev%2Fepicycles-plot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drhdev%2Fepicycles-plot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drhdev%2Fepicycles-plot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drhdev%2Fepicycles-plot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/drhdev","download_url":"https://codeload.github.com/drhdev/epicycles-plot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/drhdev%2Fepicycles-plot/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269116943,"owners_count":24362973,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-06T02:00:09.910Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-06T16:47:46.116Z","updated_at":"2025-10-16T13:17:55.393Z","avatar_url":"https://github.com/drhdev.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# epicycles-plot\n\nA Python script to generate and visualize epicycles—beautiful mathematical curves—using random parameters. The script creates high-resolution images and highlights regions based on the winding number with respect to the epicycle curve. All configuration is handled via JSON files for full reproducibility and transparency.\n\n## Features\n- Generates random epicycle curves of configurable order\n- Saves images in high resolution (default: 1000x1000 px)\n- Colors regions based on the winding number (odd: red, even: green)\n- All parameters are set via JSON input files (no code editing required)\n- Every run produces a JSON output file with all config and calculated values for perfect reproducibility\n- Robust logging to `logs/epicycles_plot.log` (overwritten each run)\n- Command line options for input, verbose logging, and help\n- **Extensive error handling and validation** for all input/output and file operations\n\n## Mathematical Background\nEpicycles are curves generated by the sum of several rotating circles (Fourier series). Historically, epicycles were used in astronomy to model planetary orbits. Mathematically, an epicycle of order $n$ can be described as:\n\n$$\n\\begin{align*}\nx(t) \u0026= \\sum_{k=1}^n r_k \\cos(f_k t + \\phi_k) \\\\\ny(t) \u0026= \\sum_{k=1}^n r_k \\sin(f_k t + \\phi_k)\n\\end{align*}\n$$\n\nwhere:\n- $r_k$ = radius of the $k$-th circle\n- $f_k$ = frequency (number of rotations)\n- $\\phi_k$ = phase offset\n- $t$ = parameter (angle)\n\nThe script also computes the **winding number** for each pixel not on the epicycle: the number of times the curve winds around that point. Pixels with an odd winding number are colored with `ODD_COLOR`, pixels with an even winding number are colored with `EVEN_COLOR`.\n\n## Installation\n\n1. **Clone the repository:**\n   ```bash\n   git clone https://github.com/drhdev/epicycles-plot.git\n   cd epicycles-plot\n   ```\n2. **Create and activate a virtual environment:**\n   ```bash\n   python3 -m venv venv\n   source venv/bin/activate\n   ```\n3. **Install the requirements:**\n   ```bash\n   pip install -r requirements.txt\n   ```\n\n## Usage\n\n### Basic usage\n```bash\npython epicycles_plot.py\n```\nThis uses the default configuration from `default-input.json`.\n\n### Custom input file\n```bash\npython epicycles_plot.py -jsoninput myparams.json\n```\n\n### Reproduce a previous run\n```bash\npython epicycles_plot.py -jsoninput output/epicycle_YYYYMMDD_HHMMSS.json\n```\n\n### Verbose logging\n```bash\npython epicycles_plot.py -v\n```\n\n### Help\n```bash\npython epicycles_plot.py -h\n```\n\n## JSON Input/Output Format\n\n### Input JSON\nThe script expects a JSON file with the following fields in the root or under a `config` key:\n\n```\n{\n  \"N_TERMS\": 6,                // (int) Number of epicycles (order, \u003e=1)\n  \"DURATION\": 6.28318530718,   // (float) Total parameter range (usually 2*pi for a full cycle)\n  \"POINTS\": 1000,              // (int) Number of points for the curve (higher = smoother)\n  \"SAVE_DIR\": \"output\",        // (str) Directory for output files\n  \"RADIUS_RANGE\": [20, 120],   // (list of 2 floats) Min/max radius for random epicycles\n  \"FREQ_RANGE\": [1, 10],       // (list of 2 ints) Min/max frequency for random epicycles\n  \"PHASE_RANGE\": [0, 6.2831],  // (list of 2 floats) Min/max phase (in radians, usually 0 to 2*pi)\n  \"IMG_WIDTH\": 1000,           // (int) Image width in pixels\n  \"IMG_HEIGHT\": 1000,          // (int) Image height in pixels\n  \"BG_COLOR\": \"white\",         // (str or RGB tuple) Background color (e.g. 'white', '#000000', [1,1,1])\n  \"CURVE_COLOR\": \"black\",      // (str or RGB tuple) Color of the epicycle curve\n  \"ODD_COLOR\": \"red\",          // (str or RGB tuple) Color for odd winding number regions\n  \"EVEN_COLOR\": \"green\",       // (str or RGB tuple) Color for even winding number regions\n  \"RANDOM_SEED\": null          // (int or null) Optional: set for reproducible randomness\n}\n```\n\n#### Parameter explanations\n- **N_TERMS**: Number of epicycles (order). Higher = more complex curves. Must be \u003e= 1 (integer).\n- **DURATION**: Range for parameter t. Use $2\\pi$ for a full cycle. Larger values = more windings. (float, \u003e0)\n- **POINTS**: Number of points to sample the curve. Higher = smoother, but slower. Must be \u003e=2 (integer).\n- **SAVE_DIR**: Output directory for images and JSON files. (string, must be writable)\n- **RADIUS_RANGE**: Range for random radii of each epicycle. Both values \u003e= 0, [min, max]. (list of two floats)\n- **FREQ_RANGE**: Range for random integer frequencies. Both values \u003e= 1, [min, max]. (list of two ints)\n- **PHASE_RANGE**: Range for random phase offsets (in radians). Usually [0, 2*pi]. (list of two floats)\n- **IMG_WIDTH/IMG_HEIGHT**: Output image size in pixels. Must be \u003e=10 (integers).\n- **BG_COLOR**: Background color. Can be a color name, hex string, or RGB tuple/list.\n- **CURVE_COLOR**: Color of the epicycle curve. Same format as BG_COLOR.\n- **ODD_COLOR**: Color for regions with odd winding number. Same format as BG_COLOR.\n- **EVEN_COLOR**: Color for regions with even winding number. Same format as BG_COLOR.\n- **RANDOM_SEED**: Optional integer for reproducible randomness. Use null for random each run.\n\n**All parameters are type-checked and validated.** If a parameter is missing, of the wrong type, or out of range, the script will log an error and abort.\n\n### Output JSON\nAfter each run, a JSON file is written to the output directory with the same basename as the image, containing:\n- The full config used (`config`)\n- All calculated values (`calculated`) needed to exactly reproduce the image\n\nYou can use this output JSON as input to reproduce the exact same image:\n```bash\npython epicycles_plot.py -jsoninput output/epicycle_YYYYMMDD_HHMMSS.json\n```\n\n### Example input JSON\nSee `default-input.json` in this repository for a ready-to-use example.\n\n## Logging\n- All steps, errors, and results are logged to `logs/epicycles_plot.log` (overwritten each run).\n- Use `-v` or `--verbose` to also print log entries to the screen.\n- Errors and missing/invalid parameters are logged and shown to the user.\n- Log format is compatible with log analyzers.\n- **All file and calculation errors are logged with details.**\n\n## Error Handling\n- The script checks for the existence, readability, and validity of the input JSON before running.\n- All parameters are type-checked and validated for allowed ranges and types.\n- Output directories and files are checked for writability; errors are logged and abort the script.\n- All exceptions are logged with details and the script exits with a clear message and exit code.\n- If an error occurs, the script exits with a clear message and log entry.\n\n## Example Output Files\n\nThe script generates PNG and JSON output files in the `output/` directory. Each run creates a pair of files with the same basename (timestamped), e.g.:\n\n- `output/epicycle_YYYYMMDD_HHMMSS.png`  (the generated image)\n- `output/epicycle_YYYYMMDD_HHMMSS.json` (all parameters and calculated values)\n\nYou can open any PNG file in the `output/` folder to view the result, and use the corresponding JSON file as input to reproduce the exact same image:\n\n```bash\npython epicycles_plot.py -jsoninput output/epicycle_YYYYMMDD_HHMMSS.json\n```\n\n\u003e **Tip:** Replace `YYYYMMDD_HHMMSS` with the actual timestamp of the file you want to use. The PNG and JSON must have the same basename.\n\n---\n\n### Output Example\n- Image: `output/epicycle_20250727_144132.png`\n- JSON:  `output/epicycle_20250727_144132.json`\n\n![Epicycle Output 1](output/epicycle_20250727_144132.png)\n\n## License\nGNU Public License\n\n## Acknowledgements\n- Uses [matplotlib](https://matplotlib.org/) and [numpy](https://numpy.org/)\n- Mathematical background: [Epicycles on Wikipedia](https://en.wikipedia.org/wiki/Epicycle)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrhdev%2Fepicycles-plot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdrhdev%2Fepicycles-plot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdrhdev%2Fepicycles-plot/lists"}