#include <bits/stdc++.h>
using namespace std;
long long n, xA[200010], yA[200010], ans, lastIdx;
const long long mod = 1e9 + 7;
map<long long, long long> streakIndex;
vector<vector<long long> > gr;
bool was[200010], isTree;
void fix(long long& a) {
  a %= mod;
  if (a < 0) {
    a += mod;
  }
}
void dfs(long long x, long long par, long long& tmpAns) {
  was[x] = 1;
  tmpAns *= 2;
  fix(tmpAns);
  for (auto i : gr[x]) {
    if (par == i) {
      continue;
    }
    if (was[i]) {
      isTree = 0;
      continue;
    }
    dfs(i, x, tmpAns);
  }
}
signed main() {
  ios_base::sync_with_stdio(0);
  cout.tie(0);
  cin.tie(0);
  cin >> n;
  gr.resize(2 * n + 1, vector<long long>());
  for (long long i = 0; i < n; ++i) {
    cin >> xA[i] >> yA[i];
    if (!streakIndex[xA[i]]) {
      ++lastIdx;
      streakIndex[xA[i]] = lastIdx;
    }
    if (!streakIndex[yA[i] + 2e9]) {
      ++lastIdx;
      streakIndex[yA[i] + 2e9] = lastIdx;
    }
    gr[streakIndex[xA[i]]].push_back(streakIndex[yA[i] + 2e9]);
    gr[streakIndex[yA[i] + 2e9]].push_back(streakIndex[xA[i]]);
  }
  ans = 1;
  for (long long i = 0; i < n; ++i) {
    if (!was[streakIndex[xA[i]]]) {
      isTree = 1;
      long long tmpAns = 1;
      dfs(streakIndex[xA[i]], -1, tmpAns);
      if (isTree) {
        --tmpAns;
        fix(tmpAns);
      }
      ans *= tmpAns;
      fix(ans);
    }
  }
  cout << ans << '\n';
}
