mapshaper 0.5.96 → 0.5.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ v0.5.97
2
+ * Better warnings and error messages.
3
+
1
4
  v0.5.96
2
5
  * Added colors=random option to the -classify command.
3
6
  * Added more sensible default behavior to the -classify command.
package/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.5.95";
3
+ var VERSION = "0.5.96";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -8877,12 +8877,24 @@
8877
8877
  arg = arg ? String(arg) : '';
8878
8878
  var hexStr = hexRxp.test(arg) ? arg : lookupColorName(arg);
8879
8879
  var rgb = null;
8880
- if (hexStr) rgb = parseHexColor(hexStr);
8881
- else if (rgbaRxp.test(arg)) rgb = parseRGBA(arg);
8882
- if (!testRGB(rgb)) stop("Unsupported color:", arg);
8880
+ if (hexStr) {
8881
+ rgb = parseHexColor(hexStr);
8882
+ } else if (rgbaRxp.test(arg)) {
8883
+ rgb = parseRGBA(arg);
8884
+ }
8885
+ if (rgb && !testRGB(rgb)) {
8886
+ rgb = null;
8887
+ }
8883
8888
  return rgb;
8884
8889
  }
8885
8890
 
8891
+ function validateColor(arg) {
8892
+ if (!parseColor(arg)) {
8893
+ stop("Unsupported color:", arg);
8894
+ }
8895
+ return true;
8896
+ }
8897
+
8886
8898
  function testRGB(o) {
8887
8899
  return !!o && testChannel(o.r) && testChannel(o.g) && testChannel(o.b) &&
8888
8900
  testAlpha(o.a);
@@ -9028,7 +9040,7 @@
9028
9040
  weights = normalizeWeights(weights);
9029
9041
  if (!weights) return '#eee';
9030
9042
  var blended = colors.reduce(function(memo, col, i) {
9031
- var rgb = parseColor(col);
9043
+ var rgb = validateColor(col) && parseColor(col);
9032
9044
  var w = +weights[i] || 0;
9033
9045
  memo.r += rgb.r * w;
9034
9046
  memo.g += rgb.g * w;
@@ -28870,7 +28882,8 @@ ${svg}
28870
28882
  categorical: [],
28871
28883
  sequential: [],
28872
28884
  rainbow: [],
28873
- diverging: []
28885
+ diverging: [],
28886
+ all: []
28874
28887
  };
28875
28888
  var ramps;
28876
28889
 
@@ -28890,6 +28903,19 @@ ${svg}
28890
28903
  '3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9');
28891
28904
  addCategoricalScheme('Tableau20',
28892
28905
  '4c78a89ecae9f58518ffbf7954a24b88d27ab79a20f2cf5b43989483bcb6e45756ff9d9879706ebab0acd67195fcbfd2b279a2d6a5c99e765fd8b5a5');
28906
+ index.all = [].concat(index.sequential, index.rainbow, index.diverging, index.categorical);
28907
+
28908
+ }
28909
+
28910
+ function standardName(name) {
28911
+ if (!name) return null;
28912
+ var lcname = name.toLowerCase();
28913
+ for (var i=0; i<index.all.length; i++) {
28914
+ if (index.all[i].toLowerCase() == lcname) {
28915
+ return index.all[i];
28916
+ }
28917
+ }
28918
+ return null;
28893
28919
  }
28894
28920
 
28895
28921
  function addSchemesFromD3(type, names) {
@@ -28944,9 +28970,26 @@ ${svg}
28944
28970
  print ('\nMulti-hue/rainbow\n' + formatStringsAsGrid(index.rainbow));
28945
28971
  }
28946
28972
 
28973
+ function pickRandomColorScheme(type) {
28974
+ initSchemes();
28975
+ var names = index[type];
28976
+ if (!names) error('Unknown color scheme type:', type);
28977
+ var i = Math.floor(Math.random() * names.length);
28978
+ return names[i];
28979
+ }
28980
+
28981
+ function getRandomColors(n) {
28982
+ initSchemes();
28983
+ var colors = getCategoricalColorScheme('Tableau20', 20);
28984
+ utils.shuffle(colors);
28985
+ colors = wrapColors(colors, n);
28986
+ return colors.slice(0, n);
28987
+ }
28988
+
28947
28989
  function getCategoricalColorScheme(name, n) {
28948
28990
  var colors;
28949
28991
  initSchemes();
28992
+ name = standardName(name);
28950
28993
  if (!isColorSchemeName(name)) {
28951
28994
  stop('Unknown color scheme name:', name);
28952
28995
  } else if (isCategoricalColorScheme(name)) {
@@ -28973,17 +29016,17 @@ ${svg}
28973
29016
 
28974
29017
  function isColorSchemeName(name) {
28975
29018
  initSchemes();
28976
- return index.categorical.includes(name) || index.sequential.includes(name) ||
28977
- index.diverging.includes(name) || index.rainbow.includes(name);
29019
+ return index.all.includes(standardName(name));
28978
29020
  }
28979
29021
 
28980
29022
  function isCategoricalColorScheme(name) {
28981
29023
  initSchemes();
28982
- return index.categorical.includes(name);
29024
+ return index.categorical.includes(standardName(name));
28983
29025
  }
28984
29026
 
28985
29027
  function getColorRamp(name, n, stops) {
28986
29028
  initSchemes();
29029
+ name = standardName(name);
28987
29030
  var lib = require('d3-scale-chromatic');
28988
29031
  var ramps = lib['scheme' + name];
28989
29032
  var interpolate = lib['interpolate' + name];
@@ -29018,45 +29061,41 @@ ${svg}
29018
29061
 
29019
29062
  function getClassValues(method, n, opts) {
29020
29063
  var categorical = method == 'categorical' || method == 'non-adjacent';
29021
- var colorArg = opts.colors ? opts.colors[0] : null;
29064
+ var colorArg = opts.colors && opts.colors.length == 1 ? opts.colors[0] : null;
29022
29065
  var colorScheme;
29023
29066
 
29024
- if (isColorSchemeName(colorArg)) {
29067
+ if (colorArg == 'random') {
29068
+ if (categorical) {
29069
+ return getRandomColors(n);
29070
+ }
29071
+ colorScheme = pickRandomColorScheme('sequential');
29072
+ message('Randomly selected color ramp:', colorScheme);
29073
+ } else if (isColorSchemeName(colorArg)) {
29025
29074
  colorScheme = colorArg;
29026
- } else if (colorArg == 'random') {
29027
- colorScheme = categorical ? 'Tableau20' : 'BuGn'; // TODO: randomize
29075
+ } else if (colorArg && !parseColor(colorArg)) {
29076
+ stop('Unrecognized color scheme name:', colorArg);
29028
29077
  } else if (opts.colors) {
29029
- // validate colors
29030
- opts.colors.forEach(parseColor);
29078
+ opts.colors.forEach(validateColor);
29031
29079
  }
29032
29080
 
29033
- if (categorical) {
29034
- if (colorScheme && isCategoricalColorScheme(colorScheme)) {
29081
+ if (colorScheme) {
29082
+ if (categorical && isCategoricalColorScheme(colorScheme)) {
29035
29083
  return getCategoricalColorScheme(colorScheme, n);
29036
- } else if (colorScheme) {
29037
- // assume we have a sequential ramp
29084
+ } else {
29038
29085
  return getColorRamp(colorScheme, n, opts.stops);
29039
- } else if (opts.colors || opts.values) {
29086
+ }
29087
+ } else if (opts.colors || opts.values) {
29088
+ if (categorical) {
29040
29089
  return getCategoricalValues(opts.colors || opts.values, n);
29041
29090
  } else {
29042
- // numerical indexes seem to make sense for non-adjacent and categorical colors
29043
- return getIndexes(n);
29044
- }
29045
- } else {
29046
- // sequential values
29047
- if (colorScheme) {
29048
- return getColorRamp(colorScheme, n, opts.stops);
29049
- } else if (opts.colors || opts.values) {
29050
29091
  return getInterpolableValues(opts.colors || opts.values, n, opts);
29051
- } else {
29052
- // TODO: rethink this
29053
- // return getInterpolableValues([0, 1], n, opts);
29054
- return getIndexes(n);
29055
29092
  }
29093
+ } else {
29094
+ // use numerical class indexes (0, 1, ...) if no values are given
29095
+ return getIndexes(n);
29056
29096
  }
29057
29097
  }
29058
29098
 
29059
-
29060
29099
  function getCategoricalValues(values, n) {
29061
29100
  if (n != values.length) {
29062
29101
  stop('Mismatch in number of categories and number of values');
@@ -29107,7 +29146,8 @@ ${svg}
29107
29146
  } else if (dataFieldType == 'number') {
29108
29147
  method = 'quantile'; // TODO: validate data field
29109
29148
  } else {
29110
- stop('Unable to determine which classification method to use.');
29149
+ // stop('Unable to determine which classification method to use.');
29150
+ stop('Missing a data field and/or classification method');
29111
29151
  }
29112
29152
  if (!all.includes(method)) {
29113
29153
  stop('Not a recognized classification method:', method);
@@ -31140,7 +31180,11 @@ ${svg}
31140
31180
  if (!opts.force && !opts.prefix) {
31141
31181
  // overwrite existing fields if the "force" option is set.
31142
31182
  // prefix also overwrites... TODO: consider changing this
31143
- joinFields = utils.difference(joinFields, destFields);
31183
+ var duplicateFields = utils.intersection(joinFields, destFields);
31184
+ if (duplicateFields.length > 0) {
31185
+ message('Same-named fields not joined without the "force" flag:', duplicateFields);
31186
+ joinFields = utils.difference(joinFields, duplicateFields);
31187
+ }
31144
31188
  }
31145
31189
  return joinFields;
31146
31190
  }
@@ -31872,7 +31916,7 @@ ${svg}
31872
31916
  // stop("Missing required colors parameter");
31873
31917
  // }
31874
31918
  if (Array.isArray(opts.colors)) {
31875
- opts.colors.forEach(parseColor); // validate colors
31919
+ opts.colors.forEach(validateColor);
31876
31920
  }
31877
31921
 
31878
31922
  var records = lyr.data ? lyr.data.getRecords() : [];
@@ -32111,7 +32155,7 @@ ${svg}
32111
32155
  var name = cmdOpts.name;
32112
32156
  var cmdDefn = externalCommands[name];
32113
32157
  if (!cmdDefn) {
32114
- stop('Unsupported command');
32158
+ stop('Unsupported command:', name);
32115
32159
  }
32116
32160
  var targetType = cmdDefn.target;
32117
32161
  var opts = parseExternalCommand(name, cmdDefn, cmdOpts._);
@@ -36891,8 +36935,12 @@ ${svg}
36891
36935
  // support multiline string of commands pasted into console
36892
36936
  str = str.split(/\n+/g).map(function(str) {
36893
36937
  var match = /^[a-z][\w-]*/.exec(str = str.trim());
36894
- if (match && parser.isCommandName(match[0])) {
36895
- str = '-' + str; // add hyphen prefix to bare command
36938
+ //if (match && parser.isCommandName(match[0])) {
36939
+ if (match) {
36940
+ // add hyphen prefix to bare command
36941
+ // also add hyphen to non-command strings, for a better error message
36942
+ // ("unsupported command" instead of "The -i command cannot be run in the browser")
36943
+ str = '-' + str;
36896
36944
  }
36897
36945
  return str;
36898
36946
  }).join(' ');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.5.96",
3
+ "version": "0.5.97",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
package/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.5.95";
3
+ var VERSION = "0.5.96";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -8877,12 +8877,24 @@
8877
8877
  arg = arg ? String(arg) : '';
8878
8878
  var hexStr = hexRxp.test(arg) ? arg : lookupColorName(arg);
8879
8879
  var rgb = null;
8880
- if (hexStr) rgb = parseHexColor(hexStr);
8881
- else if (rgbaRxp.test(arg)) rgb = parseRGBA(arg);
8882
- if (!testRGB(rgb)) stop("Unsupported color:", arg);
8880
+ if (hexStr) {
8881
+ rgb = parseHexColor(hexStr);
8882
+ } else if (rgbaRxp.test(arg)) {
8883
+ rgb = parseRGBA(arg);
8884
+ }
8885
+ if (rgb && !testRGB(rgb)) {
8886
+ rgb = null;
8887
+ }
8883
8888
  return rgb;
8884
8889
  }
8885
8890
 
8891
+ function validateColor(arg) {
8892
+ if (!parseColor(arg)) {
8893
+ stop("Unsupported color:", arg);
8894
+ }
8895
+ return true;
8896
+ }
8897
+
8886
8898
  function testRGB(o) {
8887
8899
  return !!o && testChannel(o.r) && testChannel(o.g) && testChannel(o.b) &&
8888
8900
  testAlpha(o.a);
@@ -9028,7 +9040,7 @@
9028
9040
  weights = normalizeWeights(weights);
9029
9041
  if (!weights) return '#eee';
9030
9042
  var blended = colors.reduce(function(memo, col, i) {
9031
- var rgb = parseColor(col);
9043
+ var rgb = validateColor(col) && parseColor(col);
9032
9044
  var w = +weights[i] || 0;
9033
9045
  memo.r += rgb.r * w;
9034
9046
  memo.g += rgb.g * w;
@@ -28870,7 +28882,8 @@ ${svg}
28870
28882
  categorical: [],
28871
28883
  sequential: [],
28872
28884
  rainbow: [],
28873
- diverging: []
28885
+ diverging: [],
28886
+ all: []
28874
28887
  };
28875
28888
  var ramps;
28876
28889
 
@@ -28890,6 +28903,19 @@ ${svg}
28890
28903
  '3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9');
28891
28904
  addCategoricalScheme('Tableau20',
28892
28905
  '4c78a89ecae9f58518ffbf7954a24b88d27ab79a20f2cf5b43989483bcb6e45756ff9d9879706ebab0acd67195fcbfd2b279a2d6a5c99e765fd8b5a5');
28906
+ index.all = [].concat(index.sequential, index.rainbow, index.diverging, index.categorical);
28907
+
28908
+ }
28909
+
28910
+ function standardName(name) {
28911
+ if (!name) return null;
28912
+ var lcname = name.toLowerCase();
28913
+ for (var i=0; i<index.all.length; i++) {
28914
+ if (index.all[i].toLowerCase() == lcname) {
28915
+ return index.all[i];
28916
+ }
28917
+ }
28918
+ return null;
28893
28919
  }
28894
28920
 
28895
28921
  function addSchemesFromD3(type, names) {
@@ -28944,9 +28970,26 @@ ${svg}
28944
28970
  print ('\nMulti-hue/rainbow\n' + formatStringsAsGrid(index.rainbow));
28945
28971
  }
28946
28972
 
28973
+ function pickRandomColorScheme(type) {
28974
+ initSchemes();
28975
+ var names = index[type];
28976
+ if (!names) error('Unknown color scheme type:', type);
28977
+ var i = Math.floor(Math.random() * names.length);
28978
+ return names[i];
28979
+ }
28980
+
28981
+ function getRandomColors(n) {
28982
+ initSchemes();
28983
+ var colors = getCategoricalColorScheme('Tableau20', 20);
28984
+ utils.shuffle(colors);
28985
+ colors = wrapColors(colors, n);
28986
+ return colors.slice(0, n);
28987
+ }
28988
+
28947
28989
  function getCategoricalColorScheme(name, n) {
28948
28990
  var colors;
28949
28991
  initSchemes();
28992
+ name = standardName(name);
28950
28993
  if (!isColorSchemeName(name)) {
28951
28994
  stop('Unknown color scheme name:', name);
28952
28995
  } else if (isCategoricalColorScheme(name)) {
@@ -28973,17 +29016,17 @@ ${svg}
28973
29016
 
28974
29017
  function isColorSchemeName(name) {
28975
29018
  initSchemes();
28976
- return index.categorical.includes(name) || index.sequential.includes(name) ||
28977
- index.diverging.includes(name) || index.rainbow.includes(name);
29019
+ return index.all.includes(standardName(name));
28978
29020
  }
28979
29021
 
28980
29022
  function isCategoricalColorScheme(name) {
28981
29023
  initSchemes();
28982
- return index.categorical.includes(name);
29024
+ return index.categorical.includes(standardName(name));
28983
29025
  }
28984
29026
 
28985
29027
  function getColorRamp(name, n, stops) {
28986
29028
  initSchemes();
29029
+ name = standardName(name);
28987
29030
  var lib = require('d3-scale-chromatic');
28988
29031
  var ramps = lib['scheme' + name];
28989
29032
  var interpolate = lib['interpolate' + name];
@@ -29018,45 +29061,41 @@ ${svg}
29018
29061
 
29019
29062
  function getClassValues(method, n, opts) {
29020
29063
  var categorical = method == 'categorical' || method == 'non-adjacent';
29021
- var colorArg = opts.colors ? opts.colors[0] : null;
29064
+ var colorArg = opts.colors && opts.colors.length == 1 ? opts.colors[0] : null;
29022
29065
  var colorScheme;
29023
29066
 
29024
- if (isColorSchemeName(colorArg)) {
29067
+ if (colorArg == 'random') {
29068
+ if (categorical) {
29069
+ return getRandomColors(n);
29070
+ }
29071
+ colorScheme = pickRandomColorScheme('sequential');
29072
+ message('Randomly selected color ramp:', colorScheme);
29073
+ } else if (isColorSchemeName(colorArg)) {
29025
29074
  colorScheme = colorArg;
29026
- } else if (colorArg == 'random') {
29027
- colorScheme = categorical ? 'Tableau20' : 'BuGn'; // TODO: randomize
29075
+ } else if (colorArg && !parseColor(colorArg)) {
29076
+ stop('Unrecognized color scheme name:', colorArg);
29028
29077
  } else if (opts.colors) {
29029
- // validate colors
29030
- opts.colors.forEach(parseColor);
29078
+ opts.colors.forEach(validateColor);
29031
29079
  }
29032
29080
 
29033
- if (categorical) {
29034
- if (colorScheme && isCategoricalColorScheme(colorScheme)) {
29081
+ if (colorScheme) {
29082
+ if (categorical && isCategoricalColorScheme(colorScheme)) {
29035
29083
  return getCategoricalColorScheme(colorScheme, n);
29036
- } else if (colorScheme) {
29037
- // assume we have a sequential ramp
29084
+ } else {
29038
29085
  return getColorRamp(colorScheme, n, opts.stops);
29039
- } else if (opts.colors || opts.values) {
29086
+ }
29087
+ } else if (opts.colors || opts.values) {
29088
+ if (categorical) {
29040
29089
  return getCategoricalValues(opts.colors || opts.values, n);
29041
29090
  } else {
29042
- // numerical indexes seem to make sense for non-adjacent and categorical colors
29043
- return getIndexes(n);
29044
- }
29045
- } else {
29046
- // sequential values
29047
- if (colorScheme) {
29048
- return getColorRamp(colorScheme, n, opts.stops);
29049
- } else if (opts.colors || opts.values) {
29050
29091
  return getInterpolableValues(opts.colors || opts.values, n, opts);
29051
- } else {
29052
- // TODO: rethink this
29053
- // return getInterpolableValues([0, 1], n, opts);
29054
- return getIndexes(n);
29055
29092
  }
29093
+ } else {
29094
+ // use numerical class indexes (0, 1, ...) if no values are given
29095
+ return getIndexes(n);
29056
29096
  }
29057
29097
  }
29058
29098
 
29059
-
29060
29099
  function getCategoricalValues(values, n) {
29061
29100
  if (n != values.length) {
29062
29101
  stop('Mismatch in number of categories and number of values');
@@ -29107,7 +29146,8 @@ ${svg}
29107
29146
  } else if (dataFieldType == 'number') {
29108
29147
  method = 'quantile'; // TODO: validate data field
29109
29148
  } else {
29110
- stop('Unable to determine which classification method to use.');
29149
+ // stop('Unable to determine which classification method to use.');
29150
+ stop('Missing a data field and/or classification method');
29111
29151
  }
29112
29152
  if (!all.includes(method)) {
29113
29153
  stop('Not a recognized classification method:', method);
@@ -31140,7 +31180,11 @@ ${svg}
31140
31180
  if (!opts.force && !opts.prefix) {
31141
31181
  // overwrite existing fields if the "force" option is set.
31142
31182
  // prefix also overwrites... TODO: consider changing this
31143
- joinFields = utils.difference(joinFields, destFields);
31183
+ var duplicateFields = utils.intersection(joinFields, destFields);
31184
+ if (duplicateFields.length > 0) {
31185
+ message('Same-named fields not joined without the "force" flag:', duplicateFields);
31186
+ joinFields = utils.difference(joinFields, duplicateFields);
31187
+ }
31144
31188
  }
31145
31189
  return joinFields;
31146
31190
  }
@@ -31872,7 +31916,7 @@ ${svg}
31872
31916
  // stop("Missing required colors parameter");
31873
31917
  // }
31874
31918
  if (Array.isArray(opts.colors)) {
31875
- opts.colors.forEach(parseColor); // validate colors
31919
+ opts.colors.forEach(validateColor);
31876
31920
  }
31877
31921
 
31878
31922
  var records = lyr.data ? lyr.data.getRecords() : [];
@@ -32111,7 +32155,7 @@ ${svg}
32111
32155
  var name = cmdOpts.name;
32112
32156
  var cmdDefn = externalCommands[name];
32113
32157
  if (!cmdDefn) {
32114
- stop('Unsupported command');
32158
+ stop('Unsupported command:', name);
32115
32159
  }
32116
32160
  var targetType = cmdDefn.target;
32117
32161
  var opts = parseExternalCommand(name, cmdDefn, cmdOpts._);
@@ -36891,8 +36935,12 @@ ${svg}
36891
36935
  // support multiline string of commands pasted into console
36892
36936
  str = str.split(/\n+/g).map(function(str) {
36893
36937
  var match = /^[a-z][\w-]*/.exec(str = str.trim());
36894
- if (match && parser.isCommandName(match[0])) {
36895
- str = '-' + str; // add hyphen prefix to bare command
36938
+ //if (match && parser.isCommandName(match[0])) {
36939
+ if (match) {
36940
+ // add hyphen prefix to bare command
36941
+ // also add hyphen to non-command strings, for a better error message
36942
+ // ("unsupported command" instead of "The -i command cannot be run in the browser")
36943
+ str = '-' + str;
36896
36944
  }
36897
36945
  return str;
36898
36946
  }).join(' ');