Welcome! We're thrilled that you're interested in contributing to SocialMapper. Whether you're fixing a bug, adding a feature, improving documentation, or sharing ideas, your contribution matters and helps make spatial analysis more accessible to everyone.
SocialMapper is a community-driven project, and we believe the best software comes from diverse perspectives and collaborative development. This guide will help you get started contributing to our Python toolkit for spatial analysis and demographic mapping.
- Code of Conduct
- Ways to Contribute
- Getting Started
- Development Guidelines
- Making Your Contribution
- Testing
- Documentation
- Release Process
- Getting Help
- Recognition
We are committed to providing a welcoming and inspiring community for all. By participating in this project, you agree to abide by our Code of Conduct:
We pledge to make participation in our project a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
- Use welcoming and inclusive language
- Be respectful of differing viewpoints and experiences
- Gracefully accept constructive criticism
- Focus on what is best for the community
- Show empathy towards other community members
- Harassment, discriminatory language, and personal attacks
- Publishing others' private information without permission
- Conduct which could reasonably be considered inappropriate in a professional setting
Instances of unacceptable behavior may be reported by opening an issue or contacting the maintainer directly. All complaints will be reviewed and investigated promptly and fairly.
Every contribution is valuable! Here are some ways you can help:
Found something that doesn't work? Open an issue with:
- Clear title and description
- Steps to reproduce
- Expected vs actual behavior
- Your environment (Python version, OS)
Have an idea to improve SocialMapper? We'd love to hear it! Open a feature request describing:
- The problem you're trying to solve
- Your proposed solution
- Example use cases
- Fix typos or clarify explanations
- Add examples and tutorials
- Translate documentation
- Create educational content (blog posts, videos)
- Fix bugs (look for "good first issue" labels)
- Add new features
- Improve performance
- Add tests
- Improve visualizations
- Create better map styles
- Design intuitive APIs
- Write about how you use SocialMapper
- Share analysis results
- Python 3.11 or higher
- Git for version control
- A Census API key (free from api.census.gov) - only needed for census-related features
-
Fork the repository
Click the "Fork" button at the top right of the SocialMapper repository.
-
Clone your fork
git clone https://github.com/YOUR_USERNAME/socialmapper.git cd socialmapper -
Set up the development environment using uv
We use
uvfor fast, reliable Python package management:# Install uv if you haven't already pip install uv # Create virtual environment uv venv # Activate it source .venv/bin/activate # On Windows: .venv\Scripts\activate # Install SocialMapper in development mode with all dependencies uv pip install -e ".[dev]"
-
Set up pre-commit hooks (optional but recommended)
# Install pre-commit uv pip install pre-commit # Set up the git hooks pre-commit install
-
Configure environment variables
# Copy the example environment file cp .env.example .env # Edit .env and add your Census API key (if you have one)
-
Verify your setup
# Run the test suite uv run pytest tests/ -v # Verify imports work uv run python -c "from socialmapper import create_isochrone, get_poi, get_census_data, create_map; print('All imports OK')"
You're all set! 🎉
We use modern Python 3.11+ features and follow these conventions:
- Type hints for all function parameters and returns
- Pydantic v2 for data validation
- Rich for terminal output
- Line length: 100 characters (configured in
pyproject.toml) - Import sorting: Handled automatically by ruff
We use ruff for linting and formatting:
# Check code quality
uv run ruff check socialmapper/
# Fix auto-fixable issues
uv run ruff check --fix socialmapper/
# Format code
uv run ruff format socialmapper/All public functions MUST use NumPy-style docstrings. Here's our standard template:
def analyze_accessibility(
location: str | tuple[float, float],
poi_type: str,
travel_time: int = 15
) -> pd.DataFrame:
"""
Analyze accessibility to points of interest from a location.
Calculates travel times and demographic characteristics for
populations with access to specified points of interest.
Parameters
----------
location : str or tuple of float
Either a "City, State" string for geocoding or a
(latitude, longitude) tuple with coordinates.
poi_type : str
OpenStreetMap amenity type (e.g., "library", "hospital").
travel_time : int, optional
Maximum travel time in minutes, by default 15.
Must be between 1 and 120.
Returns
-------
pd.DataFrame
DataFrame with columns:
- 'poi_name': Name of the point of interest
- 'distance_km': Distance in kilometers
- 'population': Population with access
- 'demographics': Demographic breakdown
Raises
------
ValueError
If location cannot be geocoded or poi_type is invalid.
ConnectionError
If OpenStreetMap or Census API is unavailable.
Examples
--------
>>> df = analyze_accessibility("Portland, OR", "library")
>>> df['population'].sum()
125000
>>> df = analyze_accessibility((45.5152, -122.6784), "hospital",
... travel_time=20)
>>> len(df)
5
Notes
-----
This function combines multiple data sources:
1. OpenStreetMap for POI locations
2. Census API for demographic data
3. OSMNX for travel-time calculations
See Also
--------
get_poi : Retrieve points of interest
create_isochrone : Generate travel-time polygons
"""SocialMapper prioritizes performance for large-scale analyses:
- Use concurrent processing where possible (we have 4-8x speedups)
- Implement caching for expensive operations (geocoding, API calls)
- Profile before optimizing - measure first, optimize second
- Memory efficiency - use generators for large datasets
- Add benchmarks for performance-critical code
Example of adding a performance test:
@pytest.mark.benchmark
def test_isochrone_performance(benchmark):
"""Benchmark isochrone generation performance."""
result = benchmark(create_isochrone, "Portland, OR", travel_time=15)
assert result is not None
# Performance assertions
assert benchmark.stats['mean'] < 2.0 # Should complete in < 2 secondsWe maintain high code quality with comprehensive testing:
- Minimum coverage: 80% for new code
- Test types: Unit, integration, and performance tests
- Real API calls: We test against real services (not mocks) where feasible
- Test markers: Use appropriate pytest markers
@pytest.mark.unit
def test_validate_travel_time():
"""Test travel time validation logic."""
assert validate_travel_time(15) == 15
with pytest.raises(ValueError):
validate_travel_time(150) # Exceeds maximum
@pytest.mark.integration
@pytest.mark.external
def test_census_api_connection():
"""Test real Census API connectivity."""
data = get_census_data("North Carolina")
assert len(data) > 0-
Create an issue first (if one doesn't exist)
Before starting work, open an issue or comment on an existing one. This helps:
- Avoid duplicate work
- Discuss the approach
- Get early feedback
-
Create a feature branch
# Update your main branch git checkout main git pull upstream main # Create a feature branch git checkout -b feature/your-feature-name # or git checkout -b fix/issue-number-description
-
Make your changes
- Write clear, self-documenting code
- Add tests for new functionality
- Update documentation as needed
- Follow our code standards
-
Commit your changes
We follow conventional commit messages for clarity:
# Format: <type>: <description> # Examples: git commit -m "feat: Add support for bicycle isochrones" git commit -m "fix: Correct census tract boundary calculation" git commit -m "docs: Update accessibility analysis tutorial" git commit -m "test: Add integration tests for POI search" git commit -m "perf: Optimize isochrone generation with caching"
Commit message types:
feat: New featurefix: Bug fixdocs: Documentation changestest: Adding or updating testsperf: Performance improvementsrefactor: Code restructuringstyle: Code formattingchore: Maintenance tasks
Example of a good commit message:
feat: Add demographic filtering to POI analysis - Implement age and income filters for get_poi() - Add validation for demographic parameters - Include tests for edge cases - Update API documentation with examples Closes #67 -
Run tests locally
# Run all tests uv run pytest # Run specific test file uv run pytest tests/test_api.py # Run with coverage uv run pytest --cov=socialmapper --cov-report=html # Run only fast tests uv run pytest -m "not slow"
-
Push your branch
git push origin feature/your-feature-name
-
Create a Pull Request
- Go to your fork on GitHub
- Click "New Pull Request"
- Select your feature branch
- Fill out the PR template:
## Description Brief description of what this PR does. ## Related Issue Fixes #(issue number) ## Type of Change - [ ] Bug fix - [ ] New feature - [ ] Documentation update - [ ] Performance improvement ## Testing - [ ] Tests pass locally - [ ] Added new tests for changes - [ ] Updated documentation ## Screenshots (if applicable) Add any relevant screenshots here. ## Checklist - [ ] Code follows project style guidelines - [ ] Self-review completed - [ ] Documentation updated - [ ] Tests added/updated - [ ] All tests passing
After submitting your PR:
- Automated checks run (tests, linting)
- Maintainer review - usually within 48-72 hours
- Address feedback - push additional commits as needed
- Approval and merge - maintainers will merge when ready
What we look for in reviews:
- Code quality and style consistency
- Test coverage
- Documentation completeness
- Performance implications
- Security considerations
# Run all tests
uv run pytest
# Run with verbose output
uv run pytest -v
# Run specific test markers
uv run pytest -m unit # Fast unit tests only
uv run pytest -m integration # Integration tests
uv run pytest -m "not slow" # Skip slow tests
uv run pytest -m performance # Performance benchmarks
# Run tests for specific module
uv run pytest tests/test_api.py::TestCreateIsochrone
# Run with coverage report
uv run pytest --cov=socialmapper --cov-report=term-missing
# Run tests in parallel (faster)
uv run pytest -n autoPlace tests in the tests/ directory following the pattern test_*.py:
"""Test demographic analysis functions."""
import pytest
import pandas as pd
from socialmapper import analyze_demographics
class TestDemographicAnalysis:
"""Test suite for demographic analysis."""
@pytest.fixture
def sample_location(self):
"""Provide sample location for tests."""
return "Durham, NC"
@pytest.mark.unit
def test_basic_analysis(self, sample_location):
"""Test basic demographic analysis returns expected structure."""
result = analyze_demographics(sample_location)
assert isinstance(result, pd.DataFrame)
assert 'population' in result.columns
assert len(result) > 0
@pytest.mark.integration
@pytest.mark.external
def test_census_integration(self, sample_location):
"""Test integration with Census API."""
result = analyze_demographics(
sample_location,
include_census=True
)
assert 'median_income' in result.columns
assert result['median_income'].notna().any()Common fixtures are available in tests/conftest.py:
@pytest.fixture
def mock_census_data():
"""Provide mock census data for testing."""
return pd.DataFrame({
'tract': ['001', '002'],
'population': [5000, 3000],
'median_income': [65000, 45000]
})Update documentation when you:
- Add new public functions or classes
- Change function signatures or behavior
- Add new examples or use cases
- Fix documentation errors
- Add new dependencies or requirements
# Install documentation dependencies
uv pip install mkdocs mkdocs-material
# Build and serve documentation
uv run mkdocs serve
# View at http://localhost:8000docs/
├── index.md # Home page
├── tutorials/ # Step-by-step tutorials
├── reference/ # API reference
└── contributing.md # This file
We follow semantic versioning (MAJOR.MINOR.PATCH):
- MAJOR: Incompatible API changes
- MINOR: New functionality, backwards compatible
- PATCH: Bug fixes, backwards compatible
- Update version in
pyproject.toml - Update CHANGELOG.md with release notes
- Run full test suite:
uv run pytest - Build distribution:
uv run python -m build - Create git tag:
git tag -a v0.9.1 -m "Release version 0.9.1" - Push tag:
git push upstream v0.9.1
Releases are automatically deployed to PyPI when tags are pushed.
## [0.9.1] - 2025-01-15
### Added
- Bicycle mode for isochrone generation
- Caching for geocoding requests
### Fixed
- Memory leak in large POI queries
- Incorrect census tract boundaries
### Changed
- Improved performance of demographic calculations by 40%
### Deprecated
- `analyze_area()` - use `analyze_region()` instead- 🐛 Bug Reports: Open an issue
- 💬 Discussions: GitHub Discussions for general questions
- 📧 Email: Contact the maintainer for sensitive issues
- 📖 Documentation: Check our comprehensive docs
- Critical bugs: Within 24 hours
- Feature requests: Within 72 hours
- General questions: Within 1 week
- PR reviews: Within 48-72 hours
- Search first - Check if your question has been answered
- Be specific - Include error messages, code snippets, environment details
- Provide context - Explain what you're trying to achieve
- Be patient - Maintainers are volunteers
We value all contributions! Contributors are recognized in:
- README.md: Major contributors section
- Release notes: Credited for specific contributions
- GitHub insights: Automatic contribution tracking
Look for issues labeled "good first issue" - these are specifically chosen to be approachable for newcomers.
Your first PR merged? We'll add you to our contributors list! 🎉
- 🌟 Core Contributors: Regular contributors with merge rights
- 📖 Documentation Heroes: Significant documentation improvements
- 🐛 Bug Hunters: Finding and fixing critical bugs
- 🚀 Performance Champions: Major performance improvements
- 💡 Feature Creators: Implementing new capabilities
Thank you for contributing to SocialMapper! Your efforts help make spatial analysis more accessible and powerful for researchers, planners, and communities worldwide.
Together, we're building tools that help create more equitable, accessible communities.
Ready to contribute? Pick an issue, fork the repo, and let's build something amazing together!
Last updated: January 2025 | Version: 1.0.0