visidata 2.11.dev0__py3-none-any.whl → 3.0__py3-none-any.whl

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.
Files changed (253) hide show
  1. visidata/__init__.py +72 -91
  2. visidata/_input.py +263 -44
  3. visidata/_open.py +84 -29
  4. visidata/_types.py +22 -4
  5. visidata/_urlcache.py +17 -4
  6. visidata/aggregators.py +65 -25
  7. visidata/apps/__init__.py +0 -0
  8. visidata/apps/vdsql/__about__.py +8 -0
  9. visidata/apps/vdsql/__init__.py +5 -0
  10. visidata/apps/vdsql/__main__.py +27 -0
  11. visidata/apps/vdsql/_ibis.py +748 -0
  12. visidata/apps/vdsql/bigquery.py +61 -0
  13. visidata/apps/vdsql/clickhouse.py +53 -0
  14. visidata/apps/vdsql/setup.py +40 -0
  15. visidata/apps/vdsql/snowflake.py +67 -0
  16. visidata/apps/vgit/__init__.py +13 -0
  17. visidata/apps/vgit/__main__.py +3 -0
  18. visidata/apps/vgit/abort.py +23 -0
  19. visidata/apps/vgit/blame.py +76 -0
  20. visidata/apps/vgit/branch.py +153 -0
  21. visidata/apps/vgit/config.py +95 -0
  22. visidata/apps/vgit/diff.py +169 -0
  23. visidata/apps/vgit/gitsheet.py +161 -0
  24. visidata/apps/vgit/grep.py +37 -0
  25. visidata/apps/vgit/log.py +81 -0
  26. visidata/apps/vgit/main.py +55 -0
  27. visidata/apps/vgit/remote.py +57 -0
  28. visidata/apps/vgit/repos.py +71 -0
  29. visidata/apps/vgit/setup.py +37 -0
  30. visidata/apps/vgit/stash.py +69 -0
  31. visidata/apps/vgit/status.py +204 -0
  32. visidata/apps/vgit/statusbar.py +34 -0
  33. visidata/basesheet.py +59 -50
  34. visidata/canvas.py +251 -99
  35. visidata/choose.py +15 -11
  36. visidata/clean_names.py +29 -0
  37. visidata/clipboard.py +84 -18
  38. visidata/cliptext.py +220 -46
  39. visidata/cmdlog.py +89 -114
  40. visidata/color.py +142 -56
  41. visidata/column.py +134 -131
  42. visidata/ddw/input.ddw +74 -79
  43. visidata/ddw/regex.ddw +57 -0
  44. visidata/ddwplay.py +33 -14
  45. visidata/deprecated.py +77 -3
  46. visidata/desktop/visidata.desktop +7 -0
  47. visidata/editor.py +12 -6
  48. visidata/errors.py +5 -1
  49. visidata/experimental/__init__.py +0 -0
  50. visidata/experimental/diff_sheet.py +29 -0
  51. visidata/experimental/digit_autoedit.py +6 -0
  52. visidata/experimental/gdrive.py +89 -0
  53. visidata/experimental/google.py +37 -0
  54. visidata/experimental/gsheets.py +79 -0
  55. visidata/experimental/live_search.py +37 -0
  56. visidata/experimental/liveupdate.py +45 -0
  57. visidata/experimental/mark.py +133 -0
  58. visidata/experimental/noahs_tapestry/__init__.py +1 -0
  59. visidata/experimental/noahs_tapestry/tapestry.py +147 -0
  60. visidata/experimental/rownum.py +73 -0
  61. visidata/experimental/slide_cells.py +26 -0
  62. visidata/expr.py +8 -4
  63. visidata/extensible.py +32 -6
  64. visidata/features/__init__.py +0 -0
  65. visidata/features/addcol_audiometadata.py +42 -0
  66. visidata/features/addcol_histogram.py +34 -0
  67. visidata/features/canvas_save_svg.py +69 -0
  68. visidata/features/change_precision.py +46 -0
  69. visidata/features/cmdpalette.py +163 -0
  70. visidata/features/colorbrewer.py +363 -0
  71. visidata/{colorsheet.py → features/colorsheet.py} +17 -16
  72. visidata/features/command_server.py +105 -0
  73. visidata/features/currency_to_usd.py +70 -0
  74. visidata/{customdate.py → features/customdate.py} +2 -0
  75. visidata/features/dedupe.py +132 -0
  76. visidata/{describe.py → features/describe.py} +17 -15
  77. visidata/features/errors_guide.py +26 -0
  78. visidata/features/expand_cols.py +202 -0
  79. visidata/{fill.py → features/fill.py} +4 -2
  80. visidata/{freeze.py → features/freeze.py} +11 -6
  81. visidata/features/graph_seaborn.py +79 -0
  82. visidata/features/helloworld.py +10 -0
  83. visidata/features/hint_types.py +17 -0
  84. visidata/{incr.py → features/incr.py} +5 -0
  85. visidata/{join.py → features/join.py} +107 -53
  86. visidata/features/known_cols.py +21 -0
  87. visidata/features/layout.py +62 -0
  88. visidata/{melt.py → features/melt.py} +33 -21
  89. visidata/features/normcol.py +118 -0
  90. visidata/features/open_config.py +7 -0
  91. visidata/features/open_syspaste.py +18 -0
  92. visidata/features/ping.py +157 -0
  93. visidata/features/procmgr.py +208 -0
  94. visidata/features/random_sample.py +6 -0
  95. visidata/{regex.py → features/regex.py} +47 -31
  96. visidata/features/reload_every.py +55 -0
  97. visidata/features/rename_col_cascade.py +30 -0
  98. visidata/features/scroll_context.py +60 -0
  99. visidata/features/select_equal_selected.py +11 -0
  100. visidata/features/setcol_fake.py +65 -0
  101. visidata/{slide.py → features/slide.py} +75 -21
  102. visidata/features/sparkline.py +48 -0
  103. visidata/features/status_source.py +20 -0
  104. visidata/{sysedit.py → features/sysedit.py} +2 -1
  105. visidata/features/sysopen_mailcap.py +46 -0
  106. visidata/features/term_extras.py +13 -0
  107. visidata/{transpose.py → features/transpose.py} +5 -4
  108. visidata/features/type_ipaddr.py +73 -0
  109. visidata/features/type_url.py +11 -0
  110. visidata/{unfurl.py → features/unfurl.py} +9 -9
  111. visidata/{window.py → features/window.py} +2 -2
  112. visidata/form.py +50 -21
  113. visidata/freqtbl.py +81 -33
  114. visidata/fuzzymatch.py +414 -0
  115. visidata/graph.py +105 -33
  116. visidata/guide.py +180 -0
  117. visidata/help.py +75 -44
  118. visidata/hint.py +39 -0
  119. visidata/indexsheet.py +109 -0
  120. visidata/input_history.py +55 -0
  121. visidata/interface.py +58 -0
  122. visidata/keys.py +17 -16
  123. visidata/loaders/__init__.py +9 -0
  124. visidata/loaders/_pandas.py +61 -21
  125. visidata/loaders/api_airtable.py +70 -0
  126. visidata/loaders/api_bitio.py +102 -0
  127. visidata/loaders/api_matrix.py +148 -0
  128. visidata/loaders/api_reddit.py +306 -0
  129. visidata/loaders/api_zulip.py +249 -0
  130. visidata/loaders/archive.py +41 -7
  131. visidata/loaders/arrow.py +7 -7
  132. visidata/loaders/conll.py +49 -0
  133. visidata/loaders/csv.py +25 -7
  134. visidata/loaders/eml.py +3 -4
  135. visidata/loaders/f5log.py +1204 -0
  136. visidata/loaders/fec.py +325 -0
  137. visidata/loaders/fixed_width.py +3 -5
  138. visidata/loaders/frictionless.py +3 -3
  139. visidata/loaders/geojson.py +8 -5
  140. visidata/loaders/google.py +48 -0
  141. visidata/loaders/graphviz.py +4 -4
  142. visidata/loaders/hdf5.py +4 -4
  143. visidata/loaders/html.py +48 -10
  144. visidata/loaders/http.py +84 -30
  145. visidata/loaders/imap.py +20 -10
  146. visidata/loaders/jrnl.py +52 -0
  147. visidata/loaders/json.py +83 -29
  148. visidata/loaders/jsonla.py +74 -0
  149. visidata/loaders/lsv.py +15 -11
  150. visidata/loaders/mailbox.py +40 -0
  151. visidata/loaders/markdown.py +1 -3
  152. visidata/loaders/mbtiles.py +4 -5
  153. visidata/loaders/mysql.py +11 -13
  154. visidata/loaders/npy.py +7 -7
  155. visidata/loaders/odf.py +4 -1
  156. visidata/loaders/orgmode.py +428 -0
  157. visidata/loaders/pandas_freqtbl.py +14 -20
  158. visidata/loaders/parquet.py +62 -6
  159. visidata/loaders/pcap.py +3 -3
  160. visidata/loaders/pdf.py +4 -3
  161. visidata/loaders/png.py +19 -13
  162. visidata/loaders/postgres.py +9 -8
  163. visidata/loaders/rec.py +7 -3
  164. visidata/loaders/s3.py +342 -0
  165. visidata/loaders/sas.py +5 -5
  166. visidata/loaders/scrape.py +186 -0
  167. visidata/loaders/shp.py +6 -5
  168. visidata/loaders/spss.py +5 -6
  169. visidata/loaders/sqlite.py +68 -28
  170. visidata/loaders/texttables.py +1 -1
  171. visidata/loaders/toml.py +60 -0
  172. visidata/loaders/tsv.py +61 -19
  173. visidata/loaders/ttf.py +19 -7
  174. visidata/loaders/unzip_http.py +6 -5
  175. visidata/loaders/usv.py +1 -1
  176. visidata/loaders/vcf.py +16 -16
  177. visidata/loaders/vds.py +10 -7
  178. visidata/loaders/vdx.py +30 -5
  179. visidata/loaders/xlsb.py +8 -1
  180. visidata/loaders/xlsx.py +145 -25
  181. visidata/loaders/xml.py +6 -3
  182. visidata/loaders/xword.py +4 -4
  183. visidata/loaders/yaml.py +15 -5
  184. visidata/macos.py +1 -1
  185. visidata/macros.py +130 -41
  186. visidata/main.py +119 -94
  187. visidata/mainloop.py +101 -154
  188. visidata/man/parse_options.py +2 -2
  189. visidata/man/vd.1 +302 -147
  190. visidata/man/vd.txt +291 -151
  191. visidata/memory.py +3 -3
  192. visidata/menu.py +104 -423
  193. visidata/metasheets.py +59 -141
  194. visidata/modify.py +79 -23
  195. visidata/motd.py +3 -3
  196. visidata/mouse.py +137 -0
  197. visidata/movement.py +43 -35
  198. visidata/optionssheet.py +99 -0
  199. visidata/path.py +131 -43
  200. visidata/pivot.py +74 -47
  201. visidata/plugins.py +65 -192
  202. visidata/pyobj.py +50 -201
  203. visidata/rename_col.py +20 -0
  204. visidata/save.py +42 -20
  205. visidata/search.py +54 -10
  206. visidata/selection.py +84 -5
  207. visidata/settings.py +162 -24
  208. visidata/sheets.py +229 -257
  209. visidata/shell.py +51 -21
  210. visidata/sidebar.py +162 -0
  211. visidata/sort.py +11 -4
  212. visidata/statusbar.py +113 -104
  213. visidata/stored_list.py +43 -0
  214. visidata/stored_prop.py +38 -0
  215. visidata/tests/conftest.py +3 -3
  216. visidata/tests/test_cliptext.py +39 -0
  217. visidata/tests/test_commands.py +62 -7
  218. visidata/tests/test_edittext.py +2 -2
  219. visidata/tests/test_features.py +17 -0
  220. visidata/tests/test_menu.py +14 -0
  221. visidata/tests/test_path.py +13 -4
  222. visidata/text_source.py +53 -0
  223. visidata/textsheet.py +10 -3
  224. visidata/theme.py +44 -0
  225. visidata/themes/__init__.py +0 -0
  226. visidata/themes/ascii8.py +84 -0
  227. visidata/themes/asciimono.py +84 -0
  228. visidata/themes/light.py +17 -0
  229. visidata/threads.py +87 -39
  230. visidata/tuiwin.py +22 -0
  231. visidata/type_currency.py +22 -3
  232. visidata/type_date.py +31 -9
  233. visidata/type_floatsi.py +5 -1
  234. visidata/undo.py +18 -6
  235. visidata/utils.py +106 -23
  236. visidata/vdobj.py +28 -17
  237. visidata/windows.py +10 -0
  238. visidata/wrappers.py +9 -3
  239. visidata-3.0.data/data/share/applications/visidata.desktop +7 -0
  240. {visidata-2.11.dev0.data → visidata-3.0.data}/data/share/man/man1/vd.1 +302 -147
  241. {visidata-2.11.dev0.data → visidata-3.0.data}/data/share/man/man1/visidata.1 +302 -147
  242. visidata-3.0.data/scripts/vd2to3.vdx +9 -0
  243. {visidata-2.11.dev0.dist-info → visidata-3.0.dist-info}/METADATA +13 -11
  244. visidata-3.0.dist-info/RECORD +257 -0
  245. {visidata-2.11.dev0.dist-info → visidata-3.0.dist-info}/WHEEL +1 -1
  246. {visidata-2.11.dev0.dist-info → visidata-3.0.dist-info}/entry_points.txt +0 -1
  247. visidata/layout.py +0 -44
  248. visidata/misc.py +0 -5
  249. visidata-2.11.dev0.dist-info/RECORD +0 -142
  250. /visidata/{repeat.py → features/repeat.py} +0 -0
  251. {visidata-2.11.dev0.data → visidata-3.0.data}/scripts/vd +0 -0
  252. {visidata-2.11.dev0.dist-info → visidata-3.0.dist-info}/LICENSE.gpl3 +0 -0
  253. {visidata-2.11.dev0.dist-info → visidata-3.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,363 @@
1
+ '''Colorbrewer scales for plotting in Visidata.
2
+
3
+ Thanks to:
4
+ - Prof. Cynthia Brewer et al. @ colorbrewer.org
5
+ - @dsc https://github.com/dsc/colorbrewer-python
6
+ - @MicahElliott https://gist.github.com/MicahElliott/719710
7
+ - @er1kb https://github.com/er1kb/visidata-plugins
8
+
9
+ This feature adds these commands which can be used while viewing a plot (GraphSheet):
10
+ - color-cycle: change plot colors to another palette
11
+ - color-reset:
12
+ '''
13
+ from visidata import vd, VisiData, GraphSheet, BaseSheet, Sheet, ItemColumn, CellColorizer, ENTER
14
+
15
+ # https://raw.githubusercontent.com/er1kb/colorbrewer-python/master/colorbrewer.py
16
+ # https://gist.githubusercontent.com/er1kb/02f1fee3453431d5c0ccad5e62326a99/raw/73d047f0a3ffc35f0655488547e7f24fa3f04ea6/colortrans.py
17
+
18
+ vd.option('plot_palette', 'Set3', 'colorbrewer palette to use')
19
+
20
+
21
+ colorbrewer_palettes = dict(
22
+ Accent='114 146 216 228 61 198 130 59',
23
+ Dark2='36 166 97 162 70 178 136 59',
24
+ Paired='152 31 150 70 210 160 215 208 182 60 228 130',
25
+ Pastel1='217 152 194 188 223 230 187 225 231',
26
+ Pastel2='152 223 188 224 194 229 224 188',
27
+ Set1='160 67 71 97 208 227 130 211 102',
28
+ Set2='73 209 110 176 149 220 186 145',
29
+ Set3='116 229 146 209 110 215 149 224 188 139 194 227',
30
+
31
+ YellowGreen = {
32
+ 3: '229 150 71',
33
+ 4: '230 150 114 29',
34
+ 5: '230 150 114 71 23',
35
+ 6: '230 193 150 114 71 23',
36
+ 7: '230 193 150 114 71 29 23',
37
+ 8: '230 229 193 150 114 71 29 23',
38
+ 9: '230 229 193 150 114 71 29 23 22',
39
+ },
40
+ YellowGreenBlue = {
41
+ 3: '229 115 31',
42
+ 4: '230 151 74 25',
43
+ 5: '230 151 74 31 24',
44
+ 6: '230 187 115 74 31 24',
45
+ 7: '230 187 115 74 31 25 18',
46
+ 8: '230 229 187 115 74 31 25 18',
47
+ 9: '230 229 187 115 74 31 25 24 17',
48
+ },
49
+ GreenBlue = {
50
+ 3: '194 151 74',
51
+ 4: '230 151 116 31',
52
+ 5: '230 151 116 74 25',
53
+ 6: '230 194 151 116 74 25',
54
+ 7: '230 194 151 116 74 31 25',
55
+ 8: '231 194 194 151 116 74 31 25',
56
+ 9: '231 194 194 151 116 74 31 25 24',
57
+ },
58
+ BlueGreen = {
59
+ 3: '195 116 35',
60
+ 4: '231 152 73 29',
61
+ 5: '231 152 73 35 22',
62
+ 6: '231 194 116 73 35 22',
63
+ 7: '231 194 116 73 72 29 22',
64
+ 8: '231 195 194 116 73 72 29 22',
65
+ 9: '231 195 194 116 73 72 29 22 22',
66
+ },
67
+ PurpleBlueGreen = {
68
+ 3: '225 146 30',
69
+ 4: '231 152 74 30',
70
+ 5: '231 152 74 30 23',
71
+ 6: '231 188 146 74 30 23',
72
+ 7: '231 188 146 74 67 30 23',
73
+ 8: '231 225 188 146 74 67 30 23',
74
+ 9: '231 225 188 146 74 67 30 23 23',
75
+ },
76
+ PurpleBlue = {
77
+ 3: '225 146 31',
78
+ 4: '231 152 110 25',
79
+ 5: '231 152 110 31 24',
80
+ 6: '231 188 146 110 31 24',
81
+ 7: '231 188 146 110 67 25 24',
82
+ 8: '231 225 188 146 110 67 25 24',
83
+ 9: '231 225 188 146 110 67 25 24 23',
84
+ },
85
+ BluePurple = {
86
+ 3: '195 146 97',
87
+ 4: '231 152 104 97',
88
+ 5: '231 152 104 97 90',
89
+ 6: '231 152 146 104 97 90',
90
+ 7: '231 152 146 104 97 97 53',
91
+ 8: '231 195 152 146 104 97 97 53',
92
+ 9: '231 195 152 146 104 97 97 90 53',
93
+ },
94
+ RedPurple = {
95
+ 3: '224 217 162',
96
+ 4: '230 217 205 126',
97
+ 5: '230 217 205 162 90',
98
+ 6: '230 223 217 205 162 90',
99
+ 7: '230 223 217 205 168 126 90',
100
+ 8: '231 224 223 217 205 168 126 90',
101
+ 9: '231 224 223 217 205 168 126 90 53',
102
+ },
103
+ PurpleRed = {
104
+ 3: '189 176 162',
105
+ 4: '231 182 169 161',
106
+ 5: '231 182 169 162 89',
107
+ 6: '231 182 176 169 162 89',
108
+ 7: '231 182 176 169 162 161 89',
109
+ 8: '231 189 182 176 169 162 161 89',
110
+ 9: '231 189 182 176 169 162 161 89 52',
111
+ },
112
+ OrangeRed = {
113
+ 3: '224 216 167',
114
+ 4: '230 222 209 166',
115
+ 5: '230 222 209 167 124',
116
+ 6: '230 223 216 209 167 124',
117
+ 7: '230 223 216 209 203 166 88',
118
+ 8: '231 224 223 216 209 203 166 88',
119
+ 9: '231 224 223 216 209 203 166 124 88',
120
+ },
121
+ YellowOrangeRed = {
122
+ 3: '229 215 202',
123
+ 4: '229 221 209 160',
124
+ 5: '229 221 209 202 124',
125
+ 6: '229 222 215 209 202 124',
126
+ 7: '229 222 215 209 202 160 124',
127
+ 8: '230 229 222 215 209 202 160 124',
128
+ 9: '230 229 222 215 209 202 160 124 88',
129
+ },
130
+ YellowOrangeBrown= {
131
+ 3: '229 221 166',
132
+ 4: '230 222 208 166',
133
+ 5: '230 222 208 166 94',
134
+ 6: '230 222 221 208 166 94',
135
+ 7: '230 222 221 208 202 166 88',
136
+ 8: '230 229 222 221 208 202 166 88',
137
+ 9: '230 229 222 221 208 202 166 94 52',
138
+ },
139
+ Purples = {
140
+ 3: '231 146 97',
141
+ 4: '231 188 140 61',
142
+ 5: '231 188 140 97 54',
143
+ 6: '231 189 146 140 97 54',
144
+ 7: '231 189 146 140 103 61 54',
145
+ 8: '231 231 189 146 140 103 61 54',
146
+ 9: '231 231 189 146 140 103 61 54 54',
147
+ },
148
+ Blues = {
149
+ 3: '195 152 67',
150
+ 4: '231 152 74 25',
151
+ 5: '231 152 74 67 25',
152
+ 6: '231 189 152 74 67 25',
153
+ 7: '231 189 152 74 68 25 24',
154
+ 8: '231 195 189 152 74 68 25 24',
155
+ 9: '231 195 189 152 74 68 25 25 23',
156
+ },
157
+ Greens = {
158
+ 3: '194 151 71',
159
+ 4: '230 151 114 29',
160
+ 5: '230 151 114 71 22',
161
+ 6: '230 187 151 114 71 22',
162
+ 7: '230 187 151 114 71 29 23',
163
+ 8: '231 194 187 151 114 71 29 23',
164
+ 9: '231 194 187 151 114 71 29 22 22',
165
+ },
166
+ Oranges = {
167
+ 3: '224 215 166',
168
+ 4: '230 216 209 166',
169
+ 5: '230 216 209 166 130',
170
+ 6: '230 223 215 209 166 130',
171
+ 7: '230 223 215 209 202 166 88',
172
+ 8: '231 224 223 215 209 202 166 88',
173
+ 9: '231 224 223 215 209 202 166 130 88',
174
+ },
175
+ Reds = {
176
+ 3: '224 209 160',
177
+ 4: '224 216 203 160',
178
+ 5: '224 216 203 160 124',
179
+ 6: '224 217 209 203 160 124',
180
+ 7: '224 217 209 203 202 160 88',
181
+ 8: '231 224 217 209 203 202 160 88',
182
+ 9: '231 224 217 209 203 202 160 124 52',
183
+ },
184
+ Greys = {
185
+ 3: '231 145 59',
186
+ 4: '231 188 102 59',
187
+ 5: '231 188 102 59 16',
188
+ 6: '231 188 145 102 59 16',
189
+ 7: '231 188 145 102 102 59 16',
190
+ 8: '231 231 188 145 102 102 59 16',
191
+ 9: '231 231 188 145 102 102 59 16 16',
192
+ },
193
+ PurpleOrange = {
194
+ 3: '215 231 104',
195
+ 4: '166 215 146 60',
196
+ 5: '166 215 231 146 60',
197
+ 6: '130 215 223 189 104 54',
198
+ 7: '130 215 223 231 189 104 54',
199
+ 8: '130 172 215 223 189 146 103 54',
200
+ 9: '130 172 215 223 231 189 146 103 54',
201
+ 10: '94 130 172 215 223 189 146 103 54 17',
202
+ 11: '94 130 172 215 223 231 189 146 103 54 17',
203
+ },
204
+ BrownGreen = {
205
+ 3: '179 231 73',
206
+ 4: '130 180 115 29',
207
+ 5: '130 180 231 115 29',
208
+ 6: '94 179 224 188 73 23',
209
+ 7: '94 179 224 231 188 73 23',
210
+ 8: '94 136 180 224 188 115 66 23',
211
+ 9: '94 136 180 224 231 188 115 66 23',
212
+ 10: '58 94 136 180 224 188 115 66 23 23',
213
+ 11: '58 94 136 180 224 231 188 115 66 23 23',
214
+ },
215
+ PurpleGreen = {
216
+ 3: '140 231 108',
217
+ 4: '96 146 151 29',
218
+ 5: '96 146 231 151 29',
219
+ 6: '90 140 188 194 108 29',
220
+ 7: '90 140 188 231 194 108 29',
221
+ 8: '90 97 146 188 194 151 71 29',
222
+ 9: '90 97 146 188 231 194 151 71 29',
223
+ 10: '53 90 97 146 188 194 151 71 29 22',
224
+ 11: '53 90 97 146 188 231 194 151 71 29 22',
225
+ },
226
+ PinkYellowGreen = {
227
+ 3: '182 231 149',
228
+ 4: '162 218 150 70',
229
+ 5: '162 218 231 150 70',
230
+ 6: '162 182 225 194 149 64',
231
+ 7: '162 182 225 231 194 149 64',
232
+ 8: '162 175 218 225 194 150 107 64',
233
+ 9: '162 175 218 225 231 194 150 107 64',
234
+ 10: '89 162 175 218 225 194 150 107 64 22',
235
+ 11: '89 162 175 218 225 231 194 150 107 64 22',
236
+ },
237
+ RedBlue = {
238
+ 3: '209 231 74',
239
+ 4: '160 216 116 25',
240
+ 5: '160 216 231 116 25',
241
+ 6: '124 209 224 189 74 25',
242
+ 7: '124 209 224 231 189 74 25',
243
+ 8: '124 167 216 224 189 116 68 25',
244
+ 9: '124 167 216 224 231 189 116 68 25',
245
+ 10: '52 124 167 216 224 189 116 68 25 23',
246
+ 11: '52 124 167 216 224 231 189 116 68 25 23',
247
+ },
248
+ RedGrey = {
249
+ 3: '209 231 102',
250
+ 4: '160 216 145 59',
251
+ 5: '160 216 231 145 59',
252
+ 6: '124 209 224 188 102 59',
253
+ 7: '124 209 224 231 188 102 59',
254
+ 8: '124 167 216 224 188 145 102 59',
255
+ 9: '124 167 216 224 231 188 145 102 59',
256
+ 10: '52 124 167 216 224 188 145 102 59 16',
257
+ 11: '52 124 167 216 224 231 188 145 102 59 16',
258
+ },
259
+ RedYellowBlue = {
260
+ 3: '209 229 110',
261
+ 4: '160 215 152 31',
262
+ 5: '160 215 229 152 31',
263
+ 6: '166 209 222 195 110 67',
264
+ 7: '166 209 222 229 195 110 67',
265
+ 8: '166 203 215 222 195 152 110 67',
266
+ 9: '166 203 215 222 229 195 152 110 67',
267
+ 10: '124 166 203 215 222 195 152 110 67 60',
268
+ 11: '124 166 203 215 222 229 195 152 110 67 60',
269
+ },
270
+ Spectral = {
271
+ 3: '209 229 114',
272
+ 4: '160 215 151 31',
273
+ 5: '160 215 229 151 31',
274
+ 6: '167 209 222 192 114 67',
275
+ 7: '167 209 222 229 192 114 67',
276
+ 8: '167 203 215 222 192 151 73 67',
277
+ 9: '167 203 215 222 229 192 151 73 67',
278
+ 10: '125 167 203 215 222 192 151 73 67 61',
279
+ 11: '125 167 203 215 222 229 192 151 73 67 61',
280
+ },
281
+ RedYellowGreen = {
282
+ 3: '209 229 113',
283
+ 4: '160 215 149 29',
284
+ 5: '160 215 229 149 29',
285
+ 6: '166 209 222 192 113 29',
286
+ 7: '166 209 222 229 192 113 29',
287
+ 8: '166 203 215 222 192 149 71 29',
288
+ 9: '166 203 215 222 229 192 149 71 29',
289
+ 10: '124 166 203 215 222 192 149 71 29 23',
290
+ 11: '124 166 203 215 222 229 192 149 71 29 23',
291
+ },
292
+ )
293
+
294
+ vd.colorbrewer_choices = [dict(key=k, colors=v) for k, v in colorbrewer_palettes.items()]
295
+
296
+
297
+ class PalettesSheet(Sheet):
298
+ colorizers = [
299
+ CellColorizer(2, None, lambda s,c,r,v: f'black on {v.value}' if c and r and c.name.startswith('c') else None)
300
+ ]
301
+ columns = [
302
+ ItemColumn('name', 0),
303
+ ItemColumn('n', 1, type=int),
304
+ ] + [
305
+ ItemColumn(f'c{i}', i+1)
306
+ for i in range(1, 13)
307
+ ]
308
+
309
+ def iterload(self):
310
+ for palname, pals in colorbrewer_palettes.items():
311
+ if isinstance(pals, str):
312
+ yield [palname, len(pals.split())] + pals.split()
313
+ else:
314
+ for n, pal in pals.items():
315
+ yield [palname, n] + pal.split()
316
+
317
+
318
+ @GraphSheet.api
319
+ def cycle_palette(obj):
320
+ pals = list(colorbrewer_palettes.keys())
321
+ i = pals.index(obj.options.plot_palette)
322
+ i = (i+1)%len(pals)
323
+ n = len(obj.legends) if getattr(obj, 'legends', None) else 8
324
+ obj.set_palette(pals[i], n)
325
+
326
+
327
+ @GraphSheet.api
328
+ def set_palette(obj, palname, n):
329
+ r = colorbrewer_palettes[palname]
330
+ if not isinstance(r, str):
331
+ n = max(n, min(r.keys()))
332
+ n = min(n, max(r.keys()))
333
+ r = r[n]
334
+
335
+ vd.status(f'Using {palname} {n}-color palette')
336
+ obj.options.plot_palette = palname
337
+ obj.options.plot_colors = r
338
+
339
+ if isinstance(obj, GraphSheet):
340
+ obj.reload()
341
+
342
+
343
+ VisiData.set_palette = GraphSheet.set_palette
344
+ VisiData.cycle_palette = GraphSheet.cycle_palette
345
+
346
+
347
+ BaseSheet.addCommand(None, 'open-palettes', 'vd.push(PalettesSheet("palettes", source=vd))', 'open color palettes sheet for graphs')
348
+ BaseSheet.addCommand(None, 'cycle-palette', 'vd.cycle_palette()', 'cycle to next color palette for graphs')
349
+ BaseSheet.addCommand(None, 'unset-palette', 'vd.options.unset("plot_colors")', 'reset to default color palette for graphs')
350
+
351
+ GraphSheet.addCommand('C', 'open-palettes-sheet', 'vd.push(PalettesSheet("palettes", source=sheet))', 'open color palettes sheet for this graph')
352
+ GraphSheet.addCommand('zc', 'cycle-palette-sheet', 'sheet.cycle_palette()', 'cycle to next color palette for this graph')
353
+ GraphSheet.addCommand(None, 'unset-palette-sheet', 'sheet.options.unset("plot_colors"); reload()', 'reset to default color palette for this graph')
354
+
355
+ PalettesSheet.addCommand(ENTER, 'choose-palette', 'source.set_palette(cursorRow[0], cursorRow[1])', 'set current palette for source graph')
356
+
357
+ vd.addMenuItems('''
358
+ Plot > Palette > cycle > cycle-palette-sheet
359
+ Plot > Palette > unset > unset-palette-sheet
360
+ Plot > Palette > choose > open-palettes
361
+ ''')
362
+
363
+ vd.addGlobals(PalettesSheet=PalettesSheet)
@@ -1,42 +1,43 @@
1
1
  import curses
2
- from visidata import VisiData, colors, Sheet, Column, RowColorizer, wrapply, BaseSheet
2
+ from visidata import VisiData, colors, Sheet, Column, ItemColumn, RowColorizer, wrapply, BaseSheet
3
3
 
4
4
 
5
5
  class ColorSheet(Sheet):
6
- rowtype = 'colors' # rowdef: [(fg,bg), (color_attr, colornamestr)]
6
+ rowtype = 'colors' # rowdef: [fg, bg, color_attr, colornamestr]
7
7
  columns = [
8
- Column('color', getter=lambda c,r: r[1][1]),
9
- Column('fg', type=int, getter=lambda c,r: r[0][0]),
10
- Column('bg', type=int, getter=lambda c,r: r[0][1]),
11
- Column('attr', width=0, type=int, getter=lambda c,r: r[1][0]),
12
- ]
8
+ ItemColumn('fg', 0, type=int),
9
+ ItemColumn('bg', 1, type=int),
10
+ ItemColumn('pairnum', 2),
11
+ ItemColumn('name', 3),
12
+ ]
13
13
  colorizers = [
14
- RowColorizer(7, None, lambda s,c,r,v: r and r[1][1])
14
+ RowColorizer(7, None, lambda s,c,r,v: r and r[3])
15
15
  ]
16
16
 
17
17
  def iterload(self):
18
18
  self.rows = []
19
19
  for k, v in colors.color_pairs.items():
20
- yield [k, v]
20
+ fg, bg = k
21
+ pairnum, colorname = v
22
+ yield [fg, bg, pairnum, colorname]
21
23
 
22
24
  for i in range(0, 256):
23
- yield [(i, 0), (None, f'{i}')]
25
+ yield [i, 0, None, f'{i}']
24
26
 
25
27
  def draw(self, scr):
26
28
  super().draw(scr)
27
29
  rightcol = max(self._visibleColLayout.values())
28
30
  xstart = rightcol[0] + rightcol[1] + 4
29
31
  for i, r in enumerate(self.rows[(self.topRowIndex//6)*6:(self.bottomRowIndex//6+1)*6]):
32
+ fg, bg, _, colorstr = r
33
+ s = f'█▌{fg:3}▐█'
30
34
  y=i//6+1
31
- x=(i%6)*3+xstart
32
- c = r[1][1]
33
- s = '██'
35
+ x=(i%6)*(len(s)+2)+xstart
34
36
  if y > self.windowHeight-1:
35
37
  break
36
38
  if r is self.cursorRow:
37
- x -= 1
38
- s = '[██]'
39
- scr.addstr(y, x, s, colors[c])
39
+ s = f'█[{fg:3}]█'
40
+ scr.addstr(y, x, s, colors[colorstr].attr)
40
41
 
41
42
 
42
43
  BaseSheet.addCommand(None, 'open-colors', 'vd.push(vd.colorsSheet)', 'open Color Sheet with available terminal colors')
@@ -0,0 +1,105 @@
1
+ import io
2
+ import json
3
+ import socket
4
+ from unittest.mock import Mock
5
+
6
+ from visidata import vd, VisiData, asyncthread, asyncignore, CommandLogRow, Sheet
7
+
8
+
9
+ vd.option('server_addr', '127.0.0.1', 'IP address to listen for commands', sheettype=None, replay=False)
10
+ vd.option('server_port', 0, 'port to listen for commands', sheettype=None, replay=False)
11
+
12
+
13
+ class SocketIO(io.RawIOBase):
14
+ def __init__(self, sock):
15
+ self.sock = sock
16
+
17
+ def read(self, sz=-1):
18
+ if (sz == -1): sz=0x7FFFFFFF
19
+ return self.sock.recv(sz)
20
+
21
+ def seekable(self):
22
+ return False
23
+
24
+
25
+ @VisiData.before
26
+ def mainloop(vd, scr):
27
+ port = vd.options.server_port
28
+ if port:
29
+ vd.command_listener(vd.options.server_addr, port)
30
+
31
+
32
+ @VisiData.api
33
+ @asyncignore
34
+ def command_listener(vd, addr, port):
35
+ while True:
36
+ s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
37
+ s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
38
+ s.bind((addr, port))
39
+ s.listen(1)
40
+
41
+ conn, (addr, inport) = s.accept()
42
+ vd.status(f'Connection from {addr}:{inport}')
43
+ vd.queueCommand('no-op') # update screen
44
+ vd.command_server(conn)
45
+
46
+
47
+ @VisiData.api
48
+ @asyncignore
49
+ def command_server(vd, conn):
50
+ for line in SocketIO(conn):
51
+ line = line.decode().strip()
52
+ if line == 'draw':
53
+ r = '\n'.join(json.dumps(d) for d in vd.sheet.capture_draw_object())
54
+ conn.send(r.encode('utf-8')+b'\n')
55
+ elif line.startswith('{'):
56
+ cmd = json.loads(line)
57
+ vd.queueCommand(**cmd)
58
+ else:
59
+ longname, *rest = line.split(' ', maxsplit=1)
60
+ cmd = dict(longname=longname, input=rest[0] if rest else '')
61
+ vd.queueCommand(**cmd)
62
+
63
+ conn.close()
64
+
65
+
66
+ @Sheet.api
67
+ def capture_draw_object(sheet, topRowIndex=0, nScreenRows=25):
68
+ 'capture interface at the object level'
69
+ isNull = sheet.isNullFunc()
70
+ sortkeys = {col:rev for col, rev in sheet._ordering}
71
+ rows = sheet.rows[topRowIndex:min(topRowIndex+nScreenRows+1, sheet.nRows)]
72
+
73
+ for vcolidx, col in enumerate(sheet.visibleCols):
74
+ colstate = col.__getstate__()
75
+
76
+ if col in sortkeys:
77
+ colstate['sort'] = 'desc' if sortkeys.get(col) else 'asc'
78
+
79
+ yield dict(i=vcolidx, _type='column', **colstate)
80
+
81
+ for rowidx, row in enumerate(rows):
82
+ rowstate = dict()
83
+
84
+ for notefunc in vd.rowNoters:
85
+ ch = notefunc(sheet, row)
86
+ if ch:
87
+ rowstate['note'] = rowstate.get('note', '') + ch
88
+
89
+ for vcolidx, col in enumerate(sheet.visibleCols):
90
+ cellval = col.getCell(row)
91
+
92
+ disp = ''.join(x for _, x in col.display(cellval))
93
+ cellstate = dict(display=disp)
94
+ notes = getattr(cellval, 'notes', '')
95
+ try:
96
+ if isNull and isNull(cellval.value):
97
+ notes += sheet.options.disp_note_none
98
+ except (TypeError, ValueError):
99
+ pass
100
+
101
+ if notes:
102
+ cellstate['notes'] = notes
103
+ rowstate[str(vcolidx)] = cellstate
104
+
105
+ yield dict(_type='row', i=rowidx, **rowstate)
@@ -0,0 +1,70 @@
1
+ '''Provide USD(s) function to convert string like '£300' or '205 AUD' to equivalent US$ as float.
2
+ Uses data from api.apilayer.com/fixer. Requires an API key for apilayer.com.
3
+ '''
4
+
5
+ from visidata import vd
6
+ import functools
7
+ import json
8
+
9
+ vd.option('fixer_api_key', '', 'API Key for api.apilayer.com/fixer')
10
+ vd.option('fixer_cache_days', 1, 'Cache days for currency conversions')
11
+
12
+ currency_symbols = {
13
+ '$': 'USD',
14
+ '£': 'GBP',
15
+ '₩': 'KRW',
16
+ '€': 'EUR',
17
+ '₪': 'ILS',
18
+ 'zł': 'PLN',
19
+ '₽': 'RUB',
20
+ '₫': 'VND',
21
+ }
22
+
23
+ def currency_rates_json(date='latest', base='USD'):
24
+ url = 'https://api.apilayer.com/fixer/%s?base=%s' % (date, base)
25
+ return vd.urlcache(
26
+ url,
27
+ days=vd.options.fixer_cache_days,
28
+ headers={
29
+ # First need to set some additional headers as otherwise apilayers will block it with a 403
30
+ # See also https://stackoverflow.com/questions/13303449/urllib2-httperror-http-error-403-forbidden
31
+ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11',
32
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
33
+ 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
34
+ 'Accept-Encoding': 'none',
35
+ 'Accept-Language': 'en-US,en;q=0.8',
36
+ 'Connection': 'keep-alive',
37
+
38
+ # Finally set Apikey
39
+ 'apikey': vd.options.fixer_api_key
40
+ }
41
+ ).read_text()
42
+
43
+ @functools.lru_cache()
44
+ def currency_rates():
45
+ return json.loads(currency_rates_json())['rates']
46
+
47
+ @functools.lru_cache()
48
+ def currency_multiplier(src_currency, dest_currency):
49
+ 'returns equivalent value in USD for an amt of currency_code'
50
+ if src_currency == 'USD':
51
+ return 1.0
52
+ eur_usd_mult = currency_rates()['USD']
53
+ eur_src_mult = currency_rates()[src_currency]
54
+ usd_mult = eur_usd_mult/eur_src_mult
55
+ if dest_currency == 'USD':
56
+ return usd_mult
57
+
58
+ return usd_mult/currency_rates()[dest_currency]
59
+
60
+ def USD(s):
61
+ for currency_symbol, currency_code in currency_symbols.items():
62
+ if currency_symbol in s:
63
+ amt = float(s.replace(currency_symbol, ''))
64
+ return amt*currency_multiplier(currency_code, 'USD')
65
+
66
+ amtstr, currcode = s.split(' ')
67
+ return float(amtstr) * currency_multiplier(currcode, 'USD')
68
+
69
+
70
+ vd.addGlobals(USD=USD)
@@ -21,3 +21,5 @@ def customdate(sheet, fmtstr):
21
21
 
22
22
  Sheet.addCommand('z@', 'type-customdate', 'fmt=input("date format: ", type="fmtstr"); cursorCol.type=customdate(fmt); cursorCol.fmtstr=fmt', 'set type of current column to custom date format')
23
23
  ColumnsSheet.addCommand('gz@', 'type-customdate-selected', 'fmt=input("date format: ", type="fmtstr"); onlySelectedRows.type=customdate(fmt); onlySelectedRows.fmtstr=fmt', 'set type of selected columns to date')
24
+
25
+ vd.addMenuItems('Column > Type as > custom date format > type-customdate')