edsl 0.1.39.dev3__py3-none-any.whl → 0.1.39.dev5__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.
- edsl/Base.py +413 -332
- edsl/BaseDiff.py +260 -260
- edsl/TemplateLoader.py +24 -24
- edsl/__init__.py +57 -49
- edsl/__version__.py +1 -1
- edsl/agents/Agent.py +1071 -867
- edsl/agents/AgentList.py +551 -413
- edsl/agents/Invigilator.py +284 -233
- edsl/agents/InvigilatorBase.py +257 -270
- edsl/agents/PromptConstructor.py +272 -354
- edsl/agents/QuestionInstructionPromptBuilder.py +128 -0
- edsl/agents/QuestionTemplateReplacementsBuilder.py +137 -0
- edsl/agents/__init__.py +2 -3
- edsl/agents/descriptors.py +99 -99
- edsl/agents/prompt_helpers.py +129 -129
- edsl/agents/question_option_processor.py +172 -0
- edsl/auto/AutoStudy.py +130 -117
- edsl/auto/StageBase.py +243 -230
- edsl/auto/StageGenerateSurvey.py +178 -178
- edsl/auto/StageLabelQuestions.py +125 -125
- edsl/auto/StagePersona.py +61 -61
- edsl/auto/StagePersonaDimensionValueRanges.py +88 -88
- edsl/auto/StagePersonaDimensionValues.py +74 -74
- edsl/auto/StagePersonaDimensions.py +69 -69
- edsl/auto/StageQuestions.py +74 -73
- edsl/auto/SurveyCreatorPipeline.py +21 -21
- edsl/auto/utilities.py +218 -224
- edsl/base/Base.py +279 -279
- edsl/config.py +177 -157
- edsl/conversation/Conversation.py +290 -290
- edsl/conversation/car_buying.py +59 -58
- edsl/conversation/chips.py +95 -95
- edsl/conversation/mug_negotiation.py +81 -81
- edsl/conversation/next_speaker_utilities.py +93 -93
- edsl/coop/CoopFunctionsMixin.py +15 -0
- edsl/coop/ExpectedParrotKeyHandler.py +125 -0
- edsl/coop/PriceFetcher.py +54 -54
- edsl/coop/__init__.py +2 -2
- edsl/coop/coop.py +1106 -1028
- edsl/coop/utils.py +131 -131
- edsl/data/Cache.py +573 -555
- edsl/data/CacheEntry.py +230 -233
- edsl/data/CacheHandler.py +168 -149
- edsl/data/RemoteCacheSync.py +186 -78
- edsl/data/SQLiteDict.py +292 -292
- edsl/data/__init__.py +5 -4
- edsl/data/orm.py +10 -10
- edsl/data_transfer_models.py +74 -73
- edsl/enums.py +202 -175
- edsl/exceptions/BaseException.py +21 -21
- edsl/exceptions/__init__.py +54 -54
- edsl/exceptions/agents.py +54 -42
- edsl/exceptions/cache.py +5 -5
- edsl/exceptions/configuration.py +16 -16
- edsl/exceptions/coop.py +10 -10
- edsl/exceptions/data.py +14 -14
- edsl/exceptions/general.py +34 -34
- edsl/exceptions/inference_services.py +5 -0
- edsl/exceptions/jobs.py +33 -33
- edsl/exceptions/language_models.py +63 -63
- edsl/exceptions/prompts.py +15 -15
- edsl/exceptions/questions.py +109 -91
- edsl/exceptions/results.py +29 -29
- edsl/exceptions/scenarios.py +29 -22
- edsl/exceptions/surveys.py +37 -37
- edsl/inference_services/AnthropicService.py +106 -87
- edsl/inference_services/AvailableModelCacheHandler.py +184 -0
- edsl/inference_services/AvailableModelFetcher.py +215 -0
- edsl/inference_services/AwsBedrock.py +118 -120
- edsl/inference_services/AzureAI.py +215 -217
- edsl/inference_services/DeepInfraService.py +18 -18
- edsl/inference_services/GoogleService.py +143 -148
- edsl/inference_services/GroqService.py +20 -20
- edsl/inference_services/InferenceServiceABC.py +80 -147
- edsl/inference_services/InferenceServicesCollection.py +138 -97
- edsl/inference_services/MistralAIService.py +120 -123
- edsl/inference_services/OllamaService.py +18 -18
- edsl/inference_services/OpenAIService.py +236 -224
- edsl/inference_services/PerplexityService.py +160 -163
- edsl/inference_services/ServiceAvailability.py +135 -0
- edsl/inference_services/TestService.py +90 -89
- edsl/inference_services/TogetherAIService.py +172 -170
- edsl/inference_services/data_structures.py +134 -0
- edsl/inference_services/models_available_cache.py +118 -118
- edsl/inference_services/rate_limits_cache.py +25 -25
- edsl/inference_services/registry.py +41 -41
- edsl/inference_services/write_available.py +10 -10
- edsl/jobs/AnswerQuestionFunctionConstructor.py +223 -0
- edsl/jobs/Answers.py +43 -56
- edsl/jobs/FetchInvigilator.py +47 -0
- edsl/jobs/InterviewTaskManager.py +98 -0
- edsl/jobs/InterviewsConstructor.py +50 -0
- edsl/jobs/Jobs.py +823 -898
- edsl/jobs/JobsChecks.py +172 -147
- edsl/jobs/JobsComponentConstructor.py +189 -0
- edsl/jobs/JobsPrompts.py +270 -268
- edsl/jobs/JobsRemoteInferenceHandler.py +311 -239
- edsl/jobs/JobsRemoteInferenceLogger.py +239 -0
- edsl/jobs/RequestTokenEstimator.py +30 -0
- edsl/jobs/__init__.py +1 -1
- edsl/jobs/async_interview_runner.py +138 -0
- edsl/jobs/buckets/BucketCollection.py +104 -63
- edsl/jobs/buckets/ModelBuckets.py +65 -65
- edsl/jobs/buckets/TokenBucket.py +283 -251
- edsl/jobs/buckets/TokenBucketAPI.py +211 -0
- edsl/jobs/buckets/TokenBucketClient.py +191 -0
- edsl/jobs/check_survey_scenario_compatibility.py +85 -0
- edsl/jobs/data_structures.py +120 -0
- edsl/jobs/decorators.py +35 -0
- edsl/jobs/interviews/Interview.py +396 -661
- edsl/jobs/interviews/InterviewExceptionCollection.py +99 -99
- edsl/jobs/interviews/InterviewExceptionEntry.py +186 -186
- edsl/jobs/interviews/InterviewStatistic.py +63 -63
- edsl/jobs/interviews/InterviewStatisticsCollection.py +25 -25
- edsl/jobs/interviews/InterviewStatusDictionary.py +78 -78
- edsl/jobs/interviews/InterviewStatusLog.py +92 -92
- edsl/jobs/interviews/ReportErrors.py +66 -66
- edsl/jobs/interviews/interview_status_enum.py +9 -9
- edsl/jobs/jobs_status_enums.py +9 -0
- edsl/jobs/loggers/HTMLTableJobLogger.py +304 -0
- edsl/jobs/results_exceptions_handler.py +98 -0
- edsl/jobs/runners/JobsRunnerAsyncio.py +151 -466
- edsl/jobs/runners/JobsRunnerStatus.py +297 -330
- edsl/jobs/tasks/QuestionTaskCreator.py +244 -242
- edsl/jobs/tasks/TaskCreators.py +64 -64
- edsl/jobs/tasks/TaskHistory.py +470 -450
- edsl/jobs/tasks/TaskStatusLog.py +23 -23
- edsl/jobs/tasks/task_status_enum.py +161 -163
- edsl/jobs/tokens/InterviewTokenUsage.py +27 -27
- edsl/jobs/tokens/TokenUsage.py +34 -34
- edsl/language_models/ComputeCost.py +63 -0
- edsl/language_models/LanguageModel.py +626 -668
- edsl/language_models/ModelList.py +164 -155
- edsl/language_models/PriceManager.py +127 -0
- edsl/language_models/RawResponseHandler.py +106 -0
- edsl/language_models/RegisterLanguageModelsMeta.py +184 -184
- edsl/language_models/ServiceDataSources.py +0 -0
- edsl/language_models/__init__.py +2 -3
- edsl/language_models/fake_openai_call.py +15 -15
- edsl/language_models/fake_openai_service.py +61 -61
- edsl/language_models/key_management/KeyLookup.py +63 -0
- edsl/language_models/key_management/KeyLookupBuilder.py +273 -0
- edsl/language_models/key_management/KeyLookupCollection.py +38 -0
- edsl/language_models/key_management/__init__.py +0 -0
- edsl/language_models/key_management/models.py +131 -0
- edsl/language_models/model.py +256 -0
- edsl/language_models/repair.py +156 -156
- edsl/language_models/utilities.py +65 -64
- edsl/notebooks/Notebook.py +263 -258
- edsl/notebooks/NotebookToLaTeX.py +142 -0
- edsl/notebooks/__init__.py +1 -1
- edsl/prompts/Prompt.py +352 -362
- edsl/prompts/__init__.py +2 -2
- edsl/questions/ExceptionExplainer.py +77 -0
- edsl/questions/HTMLQuestion.py +103 -0
- edsl/questions/QuestionBase.py +518 -664
- edsl/questions/QuestionBasePromptsMixin.py +221 -217
- edsl/questions/QuestionBudget.py +227 -227
- edsl/questions/QuestionCheckBox.py +359 -359
- edsl/questions/QuestionExtract.py +180 -182
- edsl/questions/QuestionFreeText.py +113 -114
- edsl/questions/QuestionFunctional.py +166 -166
- edsl/questions/QuestionList.py +223 -231
- edsl/questions/QuestionMatrix.py +265 -0
- edsl/questions/QuestionMultipleChoice.py +330 -286
- edsl/questions/QuestionNumerical.py +151 -153
- edsl/questions/QuestionRank.py +314 -324
- edsl/questions/Quick.py +41 -41
- edsl/questions/SimpleAskMixin.py +74 -73
- edsl/questions/__init__.py +27 -26
- edsl/questions/{AnswerValidatorMixin.py → answer_validator_mixin.py} +334 -289
- edsl/questions/compose_questions.py +98 -98
- edsl/questions/data_structures.py +20 -0
- edsl/questions/decorators.py +21 -21
- edsl/questions/derived/QuestionLikertFive.py +76 -76
- edsl/questions/derived/QuestionLinearScale.py +90 -87
- edsl/questions/derived/QuestionTopK.py +93 -93
- edsl/questions/derived/QuestionYesNo.py +82 -82
- edsl/questions/descriptors.py +427 -413
- edsl/questions/loop_processor.py +149 -0
- edsl/questions/prompt_templates/question_budget.jinja +13 -13
- edsl/questions/prompt_templates/question_checkbox.jinja +32 -32
- edsl/questions/prompt_templates/question_extract.jinja +11 -11
- edsl/questions/prompt_templates/question_free_text.jinja +3 -3
- edsl/questions/prompt_templates/question_linear_scale.jinja +11 -11
- edsl/questions/prompt_templates/question_list.jinja +17 -17
- edsl/questions/prompt_templates/question_multiple_choice.jinja +33 -33
- edsl/questions/prompt_templates/question_numerical.jinja +36 -36
- edsl/questions/{QuestionBaseGenMixin.py → question_base_gen_mixin.py} +168 -161
- edsl/questions/question_registry.py +177 -177
- edsl/questions/{RegisterQuestionsMeta.py → register_questions_meta.py} +71 -71
- edsl/questions/{ResponseValidatorABC.py → response_validator_abc.py} +188 -174
- edsl/questions/response_validator_factory.py +34 -0
- edsl/questions/settings.py +12 -12
- edsl/questions/templates/budget/answering_instructions.jinja +7 -7
- edsl/questions/templates/budget/question_presentation.jinja +7 -7
- edsl/questions/templates/checkbox/answering_instructions.jinja +10 -10
- edsl/questions/templates/checkbox/question_presentation.jinja +22 -22
- edsl/questions/templates/extract/answering_instructions.jinja +7 -7
- edsl/questions/templates/likert_five/answering_instructions.jinja +10 -10
- edsl/questions/templates/likert_five/question_presentation.jinja +11 -11
- edsl/questions/templates/linear_scale/answering_instructions.jinja +5 -5
- edsl/questions/templates/linear_scale/question_presentation.jinja +5 -5
- edsl/questions/templates/list/answering_instructions.jinja +3 -3
- edsl/questions/templates/list/question_presentation.jinja +5 -5
- edsl/questions/templates/matrix/__init__.py +1 -0
- edsl/questions/templates/matrix/answering_instructions.jinja +5 -0
- edsl/questions/templates/matrix/question_presentation.jinja +20 -0
- edsl/questions/templates/multiple_choice/answering_instructions.jinja +9 -9
- edsl/questions/templates/multiple_choice/question_presentation.jinja +11 -11
- edsl/questions/templates/numerical/answering_instructions.jinja +6 -6
- edsl/questions/templates/numerical/question_presentation.jinja +6 -6
- edsl/questions/templates/rank/answering_instructions.jinja +11 -11
- edsl/questions/templates/rank/question_presentation.jinja +15 -15
- edsl/questions/templates/top_k/answering_instructions.jinja +8 -8
- edsl/questions/templates/top_k/question_presentation.jinja +22 -22
- edsl/questions/templates/yes_no/answering_instructions.jinja +6 -6
- edsl/questions/templates/yes_no/question_presentation.jinja +11 -11
- edsl/results/CSSParameterizer.py +108 -108
- edsl/results/Dataset.py +587 -424
- edsl/results/DatasetExportMixin.py +594 -731
- edsl/results/DatasetTree.py +295 -275
- edsl/results/MarkdownToDocx.py +122 -0
- edsl/results/MarkdownToPDF.py +111 -0
- edsl/results/Result.py +557 -465
- edsl/results/Results.py +1183 -1165
- edsl/results/ResultsExportMixin.py +45 -43
- edsl/results/ResultsGGMixin.py +121 -121
- edsl/results/TableDisplay.py +125 -198
- edsl/results/TextEditor.py +50 -0
- edsl/results/__init__.py +2 -2
- edsl/results/file_exports.py +252 -0
- edsl/results/{ResultsFetchMixin.py → results_fetch_mixin.py} +33 -33
- edsl/results/{Selector.py → results_selector.py} +145 -135
- edsl/results/{ResultsToolsMixin.py → results_tools_mixin.py} +98 -98
- edsl/results/smart_objects.py +96 -0
- edsl/results/table_data_class.py +12 -0
- edsl/results/table_display.css +77 -77
- edsl/results/table_renderers.py +118 -0
- edsl/results/tree_explore.py +115 -115
- edsl/scenarios/ConstructDownloadLink.py +109 -0
- edsl/scenarios/DocumentChunker.py +102 -0
- edsl/scenarios/DocxScenario.py +16 -0
- edsl/scenarios/FileStore.py +511 -632
- edsl/scenarios/PdfExtractor.py +40 -0
- edsl/scenarios/Scenario.py +498 -601
- edsl/scenarios/ScenarioHtmlMixin.py +65 -64
- edsl/scenarios/ScenarioList.py +1458 -1287
- edsl/scenarios/ScenarioListExportMixin.py +45 -52
- edsl/scenarios/ScenarioListPdfMixin.py +239 -261
- edsl/scenarios/__init__.py +3 -4
- edsl/scenarios/directory_scanner.py +96 -0
- edsl/scenarios/file_methods.py +85 -0
- edsl/scenarios/handlers/__init__.py +13 -0
- edsl/scenarios/handlers/csv.py +38 -0
- edsl/scenarios/handlers/docx.py +76 -0
- edsl/scenarios/handlers/html.py +37 -0
- edsl/scenarios/handlers/json.py +111 -0
- edsl/scenarios/handlers/latex.py +5 -0
- edsl/scenarios/handlers/md.py +51 -0
- edsl/scenarios/handlers/pdf.py +68 -0
- edsl/scenarios/handlers/png.py +39 -0
- edsl/scenarios/handlers/pptx.py +105 -0
- edsl/scenarios/handlers/py.py +294 -0
- edsl/scenarios/handlers/sql.py +313 -0
- edsl/scenarios/handlers/sqlite.py +149 -0
- edsl/scenarios/handlers/txt.py +33 -0
- edsl/scenarios/{ScenarioJoin.py → scenario_join.py} +131 -127
- edsl/scenarios/scenario_selector.py +156 -0
- edsl/shared.py +1 -1
- edsl/study/ObjectEntry.py +173 -173
- edsl/study/ProofOfWork.py +113 -113
- edsl/study/SnapShot.py +80 -80
- edsl/study/Study.py +521 -528
- edsl/study/__init__.py +4 -4
- edsl/surveys/ConstructDAG.py +92 -0
- edsl/surveys/DAG.py +148 -148
- edsl/surveys/EditSurvey.py +221 -0
- edsl/surveys/InstructionHandler.py +100 -0
- edsl/surveys/Memory.py +31 -31
- edsl/surveys/MemoryManagement.py +72 -0
- edsl/surveys/MemoryPlan.py +244 -244
- edsl/surveys/Rule.py +327 -326
- edsl/surveys/RuleCollection.py +385 -387
- edsl/surveys/RuleManager.py +172 -0
- edsl/surveys/Simulator.py +75 -0
- edsl/surveys/Survey.py +1280 -1801
- edsl/surveys/SurveyCSS.py +273 -261
- edsl/surveys/SurveyExportMixin.py +259 -259
- edsl/surveys/{SurveyFlowVisualizationMixin.py → SurveyFlowVisualization.py} +181 -179
- edsl/surveys/SurveyQualtricsImport.py +284 -284
- edsl/surveys/SurveyToApp.py +141 -0
- edsl/surveys/__init__.py +5 -3
- edsl/surveys/base.py +53 -53
- edsl/surveys/descriptors.py +60 -56
- edsl/surveys/instructions/ChangeInstruction.py +48 -49
- edsl/surveys/instructions/Instruction.py +56 -65
- edsl/surveys/instructions/InstructionCollection.py +82 -77
- edsl/templates/error_reporting/base.html +23 -23
- edsl/templates/error_reporting/exceptions_by_model.html +34 -34
- edsl/templates/error_reporting/exceptions_by_question_name.html +16 -16
- edsl/templates/error_reporting/exceptions_by_type.html +16 -16
- edsl/templates/error_reporting/interview_details.html +115 -115
- edsl/templates/error_reporting/interviews.html +19 -19
- edsl/templates/error_reporting/overview.html +4 -4
- edsl/templates/error_reporting/performance_plot.html +1 -1
- edsl/templates/error_reporting/report.css +73 -73
- edsl/templates/error_reporting/report.html +117 -117
- edsl/templates/error_reporting/report.js +25 -25
- edsl/tools/__init__.py +1 -1
- edsl/tools/clusters.py +192 -192
- edsl/tools/embeddings.py +27 -27
- edsl/tools/embeddings_plotting.py +118 -118
- edsl/tools/plotting.py +112 -112
- edsl/tools/summarize.py +18 -18
- edsl/utilities/PrettyList.py +56 -0
- edsl/utilities/SystemInfo.py +28 -28
- edsl/utilities/__init__.py +22 -22
- edsl/utilities/ast_utilities.py +25 -25
- edsl/utilities/data/Registry.py +6 -6
- edsl/utilities/data/__init__.py +1 -1
- edsl/utilities/data/scooter_results.json +1 -1
- edsl/utilities/decorators.py +77 -77
- edsl/utilities/gcp_bucket/cloud_storage.py +96 -96
- edsl/utilities/interface.py +627 -627
- edsl/utilities/is_notebook.py +18 -0
- edsl/utilities/is_valid_variable_name.py +11 -0
- edsl/utilities/naming_utilities.py +263 -263
- edsl/utilities/remove_edsl_version.py +24 -0
- edsl/utilities/repair_functions.py +28 -28
- edsl/utilities/restricted_python.py +70 -70
- edsl/utilities/utilities.py +436 -424
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/LICENSE +21 -21
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/METADATA +13 -11
- edsl-0.1.39.dev5.dist-info/RECORD +358 -0
- {edsl-0.1.39.dev3.dist-info → edsl-0.1.39.dev5.dist-info}/WHEEL +1 -1
- edsl/language_models/KeyLookup.py +0 -30
- edsl/language_models/registry.py +0 -190
- edsl/language_models/unused/ReplicateBase.py +0 -83
- edsl/results/ResultsDBMixin.py +0 -238
- edsl-0.1.39.dev3.dist-info/RECORD +0 -277
@@ -1,43 +1,45 @@
|
|
1
|
-
"""Mixin class for exporting results."""
|
2
|
-
|
3
|
-
from functools import wraps
|
4
|
-
from typing import Literal, Optional, Union
|
5
|
-
|
6
|
-
from edsl.results.DatasetExportMixin import DatasetExportMixin
|
7
|
-
|
8
|
-
|
9
|
-
def to_dataset(func):
|
10
|
-
"""Convert the Results object to a Dataset object before calling the function."""
|
11
|
-
|
12
|
-
@wraps(func)
|
13
|
-
def wrapper(self, *args, **kwargs):
|
14
|
-
"""Return the function with the Results object converted to a Dataset object."""
|
15
|
-
if self.__class__.__name__ == "Results":
|
16
|
-
return func(self.select(), *args, **kwargs)
|
17
|
-
|
18
|
-
return func(self, *args, **kwargs)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
doctest
|
1
|
+
"""Mixin class for exporting results."""
|
2
|
+
|
3
|
+
from functools import wraps
|
4
|
+
from typing import Literal, Optional, Union
|
5
|
+
|
6
|
+
from edsl.results.DatasetExportMixin import DatasetExportMixin
|
7
|
+
|
8
|
+
|
9
|
+
def to_dataset(func):
|
10
|
+
"""Convert the Results object to a Dataset object before calling the function."""
|
11
|
+
|
12
|
+
@wraps(func)
|
13
|
+
def wrapper(self, *args, **kwargs):
|
14
|
+
"""Return the function with the Results object converted to a Dataset object."""
|
15
|
+
if self.__class__.__name__ == "Results":
|
16
|
+
return func(self.select(), *args, **kwargs)
|
17
|
+
elif self.__class__.__name__ == "AgentList":
|
18
|
+
return func(self.to_dataset(), *args, **kwargs)
|
19
|
+
else:
|
20
|
+
return func(self, *args, **kwargs)
|
21
|
+
|
22
|
+
wrapper._is_wrapped = True
|
23
|
+
return wrapper
|
24
|
+
|
25
|
+
|
26
|
+
def decorate_methods_from_mixin(cls, mixin_cls):
|
27
|
+
for attr_name, attr_value in mixin_cls.__dict__.items():
|
28
|
+
if callable(attr_value) and not attr_name.startswith("__"):
|
29
|
+
setattr(cls, attr_name, to_dataset(attr_value))
|
30
|
+
return cls
|
31
|
+
|
32
|
+
|
33
|
+
class ResultsExportMixin(DatasetExportMixin):
|
34
|
+
"""Mixin class for exporting Results objects."""
|
35
|
+
|
36
|
+
def __init_subclass__(cls, **kwargs):
|
37
|
+
super().__init_subclass__(**kwargs)
|
38
|
+
decorate_methods_from_mixin(cls, DatasetExportMixin)
|
39
|
+
|
40
|
+
|
41
|
+
if __name__ == "__main__":
|
42
|
+
# pass
|
43
|
+
import doctest
|
44
|
+
|
45
|
+
doctest.testmod(optionflags=doctest.ELLIPSIS)
|
edsl/results/ResultsGGMixin.py
CHANGED
@@ -1,121 +1,121 @@
|
|
1
|
-
"""Mixin class for ggplot2 plotting."""
|
2
|
-
|
3
|
-
import subprocess
|
4
|
-
import tempfile
|
5
|
-
from typing import Optional
|
6
|
-
|
7
|
-
|
8
|
-
class ResultsGGMixin:
|
9
|
-
"""Mixin class for ggplot2 plotting."""
|
10
|
-
|
11
|
-
def ggplot2(
|
12
|
-
self,
|
13
|
-
ggplot_code: str,
|
14
|
-
filename: str = None,
|
15
|
-
shape="wide",
|
16
|
-
sql: str = None,
|
17
|
-
remove_prefix: bool = True,
|
18
|
-
debug: bool = False,
|
19
|
-
height=4,
|
20
|
-
width=6,
|
21
|
-
format="svg",
|
22
|
-
factor_orders: Optional[dict] = None,
|
23
|
-
):
|
24
|
-
"""Create a ggplot2 plot from a DataFrame.
|
25
|
-
|
26
|
-
:param ggplot_code: The ggplot2 code to execute.
|
27
|
-
:param filename: The filename to save the plot to.
|
28
|
-
:param shape: The shape of the data in the DataFrame (wide or long).
|
29
|
-
:param sql: The SQL query to execute beforehand to manipulate the data.
|
30
|
-
:param remove_prefix: Whether to remove the prefix from the column names.
|
31
|
-
:param debug: Whether to print the R code instead of executing it.
|
32
|
-
:param height: The height of the plot in inches.
|
33
|
-
:param width: The width of the plot in inches.
|
34
|
-
:param format: The format to save the plot in (png or svg).
|
35
|
-
:param factor_orders: A dictionary of factor columns and their order.
|
36
|
-
"""
|
37
|
-
|
38
|
-
if sql == None:
|
39
|
-
sql = "select * from self"
|
40
|
-
|
41
|
-
if shape == "long":
|
42
|
-
df = self.sql(sql, shape="long")
|
43
|
-
elif shape == "wide":
|
44
|
-
df = self.sql(sql, shape="wide", remove_prefix=remove_prefix)
|
45
|
-
|
46
|
-
# Convert DataFrame to CSV format
|
47
|
-
csv_data = df.to_csv(index=False)
|
48
|
-
|
49
|
-
# Embed the CSV data within the R script
|
50
|
-
csv_data_escaped = csv_data.replace("\n", "\\n").replace("'", "\\'")
|
51
|
-
read_csv_code = f"self <- read.csv(text = '{csv_data_escaped}', sep = ',')\n"
|
52
|
-
|
53
|
-
if factor_orders is not None:
|
54
|
-
for factor, order in factor_orders.items():
|
55
|
-
# read_csv_code += f"""self${{{factor}}} <- factor(self${{{factor}}}, levels=c({','.join(['"{}"'.format(x) for x in order])}))"""
|
56
|
-
|
57
|
-
level_string = ", ".join([f'"{x}"' for x in order])
|
58
|
-
read_csv_code += (
|
59
|
-
f"self${factor} <- factor(self${factor}, levels=c({level_string}))"
|
60
|
-
)
|
61
|
-
read_csv_code += "\n"
|
62
|
-
|
63
|
-
# Load ggplot2 library
|
64
|
-
load_ggplot2 = "library(ggplot2)\n"
|
65
|
-
|
66
|
-
# Check if a filename is provided for the plot, if not create a temporary one
|
67
|
-
if not filename:
|
68
|
-
filename = tempfile.mktemp(suffix=f".{format}")
|
69
|
-
|
70
|
-
# Combine all R script parts
|
71
|
-
full_r_code = load_ggplot2 + read_csv_code + ggplot_code
|
72
|
-
|
73
|
-
# Add command to save the plot to a file
|
74
|
-
full_r_code += f'\nggsave("{filename}", plot = last_plot(), width = {width}, height = {height}, device = "{format}")'
|
75
|
-
|
76
|
-
if debug:
|
77
|
-
print(full_r_code)
|
78
|
-
return
|
79
|
-
|
80
|
-
result = subprocess.run(
|
81
|
-
["Rscript", "-"],
|
82
|
-
input=full_r_code,
|
83
|
-
text=True,
|
84
|
-
stdout=subprocess.PIPE,
|
85
|
-
stderr=subprocess.PIPE,
|
86
|
-
)
|
87
|
-
|
88
|
-
if result.returncode != 0:
|
89
|
-
if result.returncode == 127: # 'command not found'
|
90
|
-
raise RuntimeError(
|
91
|
-
"Rscript is probably not installed. Please install R from https://cran.r-project.org/"
|
92
|
-
)
|
93
|
-
else:
|
94
|
-
raise RuntimeError(
|
95
|
-
f"An error occurred while running Rscript: {result.stderr}"
|
96
|
-
)
|
97
|
-
|
98
|
-
if result.stderr:
|
99
|
-
print("Error in R script:", result.stderr)
|
100
|
-
else:
|
101
|
-
self._display_plot(filename, width, height)
|
102
|
-
|
103
|
-
def _display_plot(self, filename: str, width: float, height: float):
|
104
|
-
"""Display the plot in the notebook."""
|
105
|
-
import matplotlib.pyplot as plt
|
106
|
-
import matplotlib.image as mpimg
|
107
|
-
|
108
|
-
if filename.endswith(".png"):
|
109
|
-
img = mpimg.imread(filename)
|
110
|
-
plt.figure(
|
111
|
-
figsize=(width, height)
|
112
|
-
) # Set the figure size (width, height) in inches
|
113
|
-
plt.imshow(img)
|
114
|
-
plt.axis("off")
|
115
|
-
plt.show()
|
116
|
-
elif filename.endswith(".svg"):
|
117
|
-
from IPython.display import SVG, display
|
118
|
-
|
119
|
-
display(SVG(filename=filename))
|
120
|
-
else:
|
121
|
-
print("Unsupported file format. Please provide a PNG or SVG file.")
|
1
|
+
"""Mixin class for ggplot2 plotting."""
|
2
|
+
|
3
|
+
import subprocess
|
4
|
+
import tempfile
|
5
|
+
from typing import Optional
|
6
|
+
|
7
|
+
|
8
|
+
class ResultsGGMixin:
|
9
|
+
"""Mixin class for ggplot2 plotting."""
|
10
|
+
|
11
|
+
def ggplot2(
|
12
|
+
self,
|
13
|
+
ggplot_code: str,
|
14
|
+
filename: str = None,
|
15
|
+
shape="wide",
|
16
|
+
sql: str = None,
|
17
|
+
remove_prefix: bool = True,
|
18
|
+
debug: bool = False,
|
19
|
+
height=4,
|
20
|
+
width=6,
|
21
|
+
format="svg",
|
22
|
+
factor_orders: Optional[dict] = None,
|
23
|
+
):
|
24
|
+
"""Create a ggplot2 plot from a DataFrame.
|
25
|
+
|
26
|
+
:param ggplot_code: The ggplot2 code to execute.
|
27
|
+
:param filename: The filename to save the plot to.
|
28
|
+
:param shape: The shape of the data in the DataFrame (wide or long).
|
29
|
+
:param sql: The SQL query to execute beforehand to manipulate the data.
|
30
|
+
:param remove_prefix: Whether to remove the prefix from the column names.
|
31
|
+
:param debug: Whether to print the R code instead of executing it.
|
32
|
+
:param height: The height of the plot in inches.
|
33
|
+
:param width: The width of the plot in inches.
|
34
|
+
:param format: The format to save the plot in (png or svg).
|
35
|
+
:param factor_orders: A dictionary of factor columns and their order.
|
36
|
+
"""
|
37
|
+
|
38
|
+
if sql == None:
|
39
|
+
sql = "select * from self"
|
40
|
+
|
41
|
+
if shape == "long":
|
42
|
+
df = self.sql(sql, shape="long")
|
43
|
+
elif shape == "wide":
|
44
|
+
df = self.sql(sql, shape="wide", remove_prefix=remove_prefix)
|
45
|
+
|
46
|
+
# Convert DataFrame to CSV format
|
47
|
+
csv_data = df.to_csv(index=False)
|
48
|
+
|
49
|
+
# Embed the CSV data within the R script
|
50
|
+
csv_data_escaped = csv_data.replace("\n", "\\n").replace("'", "\\'")
|
51
|
+
read_csv_code = f"self <- read.csv(text = '{csv_data_escaped}', sep = ',')\n"
|
52
|
+
|
53
|
+
if factor_orders is not None:
|
54
|
+
for factor, order in factor_orders.items():
|
55
|
+
# read_csv_code += f"""self${{{factor}}} <- factor(self${{{factor}}}, levels=c({','.join(['"{}"'.format(x) for x in order])}))"""
|
56
|
+
|
57
|
+
level_string = ", ".join([f'"{x}"' for x in order])
|
58
|
+
read_csv_code += (
|
59
|
+
f"self${factor} <- factor(self${factor}, levels=c({level_string}))"
|
60
|
+
)
|
61
|
+
read_csv_code += "\n"
|
62
|
+
|
63
|
+
# Load ggplot2 library
|
64
|
+
load_ggplot2 = "library(ggplot2)\n"
|
65
|
+
|
66
|
+
# Check if a filename is provided for the plot, if not create a temporary one
|
67
|
+
if not filename:
|
68
|
+
filename = tempfile.mktemp(suffix=f".{format}")
|
69
|
+
|
70
|
+
# Combine all R script parts
|
71
|
+
full_r_code = load_ggplot2 + read_csv_code + ggplot_code
|
72
|
+
|
73
|
+
# Add command to save the plot to a file
|
74
|
+
full_r_code += f'\nggsave("{filename}", plot = last_plot(), width = {width}, height = {height}, device = "{format}")'
|
75
|
+
|
76
|
+
if debug:
|
77
|
+
print(full_r_code)
|
78
|
+
return
|
79
|
+
|
80
|
+
result = subprocess.run(
|
81
|
+
["Rscript", "-"],
|
82
|
+
input=full_r_code,
|
83
|
+
text=True,
|
84
|
+
stdout=subprocess.PIPE,
|
85
|
+
stderr=subprocess.PIPE,
|
86
|
+
)
|
87
|
+
|
88
|
+
if result.returncode != 0:
|
89
|
+
if result.returncode == 127: # 'command not found'
|
90
|
+
raise RuntimeError(
|
91
|
+
"Rscript is probably not installed. Please install R from https://cran.r-project.org/"
|
92
|
+
)
|
93
|
+
else:
|
94
|
+
raise RuntimeError(
|
95
|
+
f"An error occurred while running Rscript: {result.stderr}"
|
96
|
+
)
|
97
|
+
|
98
|
+
if result.stderr:
|
99
|
+
print("Error in R script:", result.stderr)
|
100
|
+
else:
|
101
|
+
self._display_plot(filename, width, height)
|
102
|
+
|
103
|
+
def _display_plot(self, filename: str, width: float, height: float):
|
104
|
+
"""Display the plot in the notebook."""
|
105
|
+
import matplotlib.pyplot as plt
|
106
|
+
import matplotlib.image as mpimg
|
107
|
+
|
108
|
+
if filename.endswith(".png"):
|
109
|
+
img = mpimg.imread(filename)
|
110
|
+
plt.figure(
|
111
|
+
figsize=(width, height)
|
112
|
+
) # Set the figure size (width, height) in inches
|
113
|
+
plt.imshow(img)
|
114
|
+
plt.axis("off")
|
115
|
+
plt.show()
|
116
|
+
elif filename.endswith(".svg"):
|
117
|
+
from IPython.display import SVG, display
|
118
|
+
|
119
|
+
display(SVG(filename=filename))
|
120
|
+
else:
|
121
|
+
print("Unsupported file format. Please provide a PNG or SVG file.")
|
edsl/results/TableDisplay.py
CHANGED
@@ -1,198 +1,125 @@
|
|
1
|
-
from
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
# Use example data if none provided
|
127
|
-
if headers is None:
|
128
|
-
headers = ["Name", "Age", "City", "Occupation"]
|
129
|
-
if data is None:
|
130
|
-
data = [
|
131
|
-
[
|
132
|
-
"John Doe",
|
133
|
-
30,
|
134
|
-
"New York",
|
135
|
-
"""cls: The class itself
|
136
|
-
headers (list): List of column headers. If None, uses example headers
|
137
|
-
data (list): List of data rows. If None, uses example data
|
138
|
-
filename (str): The name of the HTML file to create. Defaults to "table_example.html"
|
139
|
-
auto_open (bool): Whether to automatically open the file in the default web browser. Defaults to True
|
140
|
-
""",
|
141
|
-
],
|
142
|
-
["Jane Smith", 28, "San Francisco", "Designer"],
|
143
|
-
["Bob Johnson", 35, "Chicago", "Manager"],
|
144
|
-
["Alice Brown", 25, "Boston", "Developer"],
|
145
|
-
["Charlie Wilson", 40, "Seattle", "Architect"],
|
146
|
-
]
|
147
|
-
|
148
|
-
# Create instance with the data
|
149
|
-
instance = cls(headers=headers, data=data)
|
150
|
-
|
151
|
-
# Get the table HTML content
|
152
|
-
table_html = instance._repr_html_()
|
153
|
-
|
154
|
-
# Calculate the appropriate iframe height
|
155
|
-
num_rows = len(data)
|
156
|
-
iframe_height = min(num_rows * 140 + 50, cls.max_height)
|
157
|
-
print(f"Table height: {iframe_height}px")
|
158
|
-
|
159
|
-
# Create the full HTML document
|
160
|
-
html_content = f"""
|
161
|
-
<!DOCTYPE html>
|
162
|
-
<html>
|
163
|
-
<head>
|
164
|
-
<title>Table Display Example</title>
|
165
|
-
<style>
|
166
|
-
body {{
|
167
|
-
margin: 0;
|
168
|
-
padding: 20px;
|
169
|
-
font-family: Arial, sans-serif;
|
170
|
-
}}
|
171
|
-
iframe {{
|
172
|
-
width: 100%;
|
173
|
-
height: {iframe_height}px;
|
174
|
-
border: none;
|
175
|
-
overflow: hidden;
|
176
|
-
}}
|
177
|
-
</style>
|
178
|
-
</head>
|
179
|
-
<body>
|
180
|
-
<iframe srcdoc='{table_html}'></iframe>
|
181
|
-
</body>
|
182
|
-
</html>
|
183
|
-
"""
|
184
|
-
|
185
|
-
# Write the HTML file
|
186
|
-
abs_path = os.path.abspath(filename)
|
187
|
-
with open(filename, "w", encoding="utf-8") as f:
|
188
|
-
f.write(html_content)
|
189
|
-
|
190
|
-
# Open in browser if requested
|
191
|
-
if auto_open:
|
192
|
-
webbrowser.open("file://" + abs_path, new=2)
|
193
|
-
|
194
|
-
return abs_path
|
195
|
-
|
196
|
-
|
197
|
-
if __name__ == "__main__":
|
198
|
-
TableDisplay.example()
|
1
|
+
from typing import (
|
2
|
+
Protocol,
|
3
|
+
List,
|
4
|
+
Any,
|
5
|
+
Optional,
|
6
|
+
TYPE_CHECKING,
|
7
|
+
Sequence,
|
8
|
+
Union,
|
9
|
+
Literal,
|
10
|
+
)
|
11
|
+
|
12
|
+
if TYPE_CHECKING:
|
13
|
+
from edsl.results.Dataset import Dataset
|
14
|
+
|
15
|
+
from edsl.results.table_data_class import TableData
|
16
|
+
|
17
|
+
from edsl.results.table_renderers import DataTablesRenderer, PandasStyleRenderer
|
18
|
+
|
19
|
+
Row = Sequence[Union[str, int, float, bool, None]]
|
20
|
+
TableFormat = Literal[
|
21
|
+
"grid", "simple", "pipe", "orgtbl", "rst", "mediawiki", "html", "latex"
|
22
|
+
]
|
23
|
+
|
24
|
+
|
25
|
+
class TableRenderer(Protocol):
|
26
|
+
"""Table renderer protocol"""
|
27
|
+
|
28
|
+
def render_html(self, table_data: TableData) -> str:
|
29
|
+
pass
|
30
|
+
|
31
|
+
|
32
|
+
# Modified TableDisplay class
|
33
|
+
class TableDisplay:
|
34
|
+
def __init__(
|
35
|
+
self,
|
36
|
+
headers: Sequence[str],
|
37
|
+
data: Sequence[Row],
|
38
|
+
tablefmt: Optional[TableFormat] = None,
|
39
|
+
raw_data_set: "Dataset" = None,
|
40
|
+
renderer_class: Optional[TableRenderer] = None,
|
41
|
+
):
|
42
|
+
assert len(headers) == len(data[0]) # Check if headers and data are consistent
|
43
|
+
|
44
|
+
self.headers = headers
|
45
|
+
self.data = data
|
46
|
+
self.tablefmt = tablefmt
|
47
|
+
self.raw_data_set = raw_data_set
|
48
|
+
|
49
|
+
self.renderer_class = renderer_class or PandasStyleRenderer
|
50
|
+
|
51
|
+
# Handle printing parameters from raw_data_set
|
52
|
+
if hasattr(raw_data_set, "print_parameters"):
|
53
|
+
self.printing_parameters = (
|
54
|
+
raw_data_set.print_parameters if raw_data_set.print_parameters else {}
|
55
|
+
)
|
56
|
+
else:
|
57
|
+
self.printing_parameters = {}
|
58
|
+
|
59
|
+
def _repr_html_(self) -> str:
|
60
|
+
table_data = TableData(
|
61
|
+
headers=self.headers,
|
62
|
+
data=self.data,
|
63
|
+
parameters=self.printing_parameters,
|
64
|
+
raw_data_set=self.raw_data_set,
|
65
|
+
)
|
66
|
+
return self.renderer_class(table_data).render_html()
|
67
|
+
|
68
|
+
def __repr__(self):
|
69
|
+
from tabulate import tabulate
|
70
|
+
|
71
|
+
return tabulate(self.data, headers=self.headers, tablefmt=self.tablefmt)
|
72
|
+
|
73
|
+
@classmethod
|
74
|
+
def from_dictionary(
|
75
|
+
cls,
|
76
|
+
dictionary: dict,
|
77
|
+
tablefmt: Optional[TableFormat] = None,
|
78
|
+
renderer: Optional[TableRenderer] = None,
|
79
|
+
) -> "TableDisplay":
|
80
|
+
headers = list(dictionary.keys())
|
81
|
+
data = [list(dictionary.values())]
|
82
|
+
return cls(headers, data, tablefmt, renderer_class=renderer)
|
83
|
+
|
84
|
+
@classmethod
|
85
|
+
def from_dictionary_wide(
|
86
|
+
cls,
|
87
|
+
dictionary: dict,
|
88
|
+
tablefmt: Optional[TableFormat] = None,
|
89
|
+
renderer: Optional[TableRenderer] = None,
|
90
|
+
) -> "TableDisplay":
|
91
|
+
headers = ["key", "value"]
|
92
|
+
data = [[k, v] for k, v in dictionary.items()]
|
93
|
+
return cls(headers, data, tablefmt, renderer_class=renderer)
|
94
|
+
|
95
|
+
@classmethod
|
96
|
+
def from_dataset(
|
97
|
+
cls,
|
98
|
+
dataset: "Dataset",
|
99
|
+
tablefmt: Optional[TableFormat] = None,
|
100
|
+
renderer: Optional[TableRenderer] = None,
|
101
|
+
) -> "TableDisplay":
|
102
|
+
headers, data = dataset._tabular()
|
103
|
+
return cls(headers, data, tablefmt, dataset, renderer_class=renderer)
|
104
|
+
|
105
|
+
def long(self) -> "TableDisplay":
|
106
|
+
"""Convert to long format"""
|
107
|
+
new_header = ["row", "key", "value"]
|
108
|
+
new_data = []
|
109
|
+
for index, row in enumerate(self.data):
|
110
|
+
new_data.extend([[index, k, v] for k, v in zip(self.headers, row)])
|
111
|
+
return TableDisplay(
|
112
|
+
new_header, new_data, self.tablefmt, renderer_class=self.renderer_class
|
113
|
+
)
|
114
|
+
|
115
|
+
|
116
|
+
# Example usage:
|
117
|
+
if __name__ == "__main__":
|
118
|
+
headers = ["Name", "Age", "City"]
|
119
|
+
data = [["John", 30, "New York"], ["Jane", 25, "London"]]
|
120
|
+
|
121
|
+
# Using default (Pandas) renderer
|
122
|
+
table1 = TableDisplay(headers, data)
|
123
|
+
|
124
|
+
# Using DataTables renderer
|
125
|
+
table2 = TableDisplay(headers, data, renderer=DataTablesRenderer())
|